├── .editorconfig ├── .eslintrc.json ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .vscode ├── extensions.json └── settings.json ├── README.md ├── angular.json ├── apps ├── .gitkeep ├── naris-e2e │ ├── .eslintrc.json │ ├── cypress.json │ ├── src │ │ ├── fixtures │ │ │ └── example.json │ │ ├── integration │ │ │ └── app.spec.ts │ │ └── support │ │ │ ├── app.po.ts │ │ │ ├── commands.ts │ │ │ └── index.ts │ └── tsconfig.json └── naris │ ├── .browserslistrc │ ├── .eslintrc.json │ ├── jest.config.js │ ├── src │ ├── app │ │ ├── api │ │ │ ├── by-route-path.resolver.spec.ts │ │ │ ├── by-route-path.resolver.ts │ │ │ ├── json.dto.helpers.ts │ │ │ ├── jsonDto.model.ts │ │ │ ├── progress │ │ │ │ ├── events │ │ │ │ │ └── watch-video.event.ts │ │ │ │ ├── personal-activity.service.spec.ts │ │ │ │ ├── personal-activity.service.ts │ │ │ │ └── progress.const.ts │ │ │ ├── questions │ │ │ │ └── question.model.ts │ │ │ ├── streams │ │ │ │ ├── stream.model.ts │ │ │ │ ├── stream.service.spec.ts │ │ │ │ └── stream.service.ts │ │ │ ├── targets │ │ │ │ └── target.interface.ts │ │ │ ├── tasks │ │ │ │ ├── tasks.resolver.spec.ts │ │ │ │ └── tasks.resolver.ts │ │ │ ├── workbook │ │ │ │ └── workbook.model.ts │ │ │ └── workshops │ │ │ │ └── workshops.service.ts │ │ ├── app-routing.module.ts │ │ ├── app.component.html │ │ ├── app.component.scss │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── nx-welcome.component.ts │ │ ├── pages │ │ │ ├── components │ │ │ │ └── files-list │ │ │ │ │ ├── files-list.component.html │ │ │ │ │ ├── files-list.component.scss │ │ │ │ │ ├── files-list.component.spec.ts │ │ │ │ │ └── files-list.component.ts │ │ │ ├── default │ │ │ │ ├── default.component.html │ │ │ │ ├── default.component.scss │ │ │ │ ├── default.component.spec.ts │ │ │ │ ├── default.component.ts │ │ │ │ ├── menu.const.ts │ │ │ │ └── mobile-menu │ │ │ │ │ ├── mobile-menu.component.html │ │ │ │ │ ├── mobile-menu.component.scss │ │ │ │ │ ├── mobile-menu.component.spec.ts │ │ │ │ │ └── mobile-menu.component.ts │ │ │ ├── demo.module.ts │ │ │ ├── dumb │ │ │ │ ├── access-denied │ │ │ │ │ ├── access-denied.component.html │ │ │ │ │ ├── access-denied.component.scss │ │ │ │ │ ├── access-denied.component.spec.ts │ │ │ │ │ └── access-denied.component.ts │ │ │ │ ├── audio-player │ │ │ │ │ ├── audio-player.component.html │ │ │ │ │ ├── audio-player.component.scss │ │ │ │ │ ├── audio-player.component.spec.ts │ │ │ │ │ └── audio-player.component.ts │ │ │ │ ├── dumb.module.ts │ │ │ │ ├── no-content │ │ │ │ │ ├── no-content.component.html │ │ │ │ │ ├── no-content.component.scss │ │ │ │ │ └── no-content.component.ts │ │ │ │ ├── overlay │ │ │ │ │ ├── overlay.component.html │ │ │ │ │ ├── overlay.component.scss │ │ │ │ │ ├── overlay.component.spec.ts │ │ │ │ │ └── overlay.component.ts │ │ │ │ ├── sr-text-edit │ │ │ │ │ ├── sr-text-edit.component.scss │ │ │ │ │ └── sr-text-edit.component.ts │ │ │ │ ├── under-development │ │ │ │ │ ├── under-development.component.html │ │ │ │ │ ├── under-development.component.scss │ │ │ │ │ ├── under-development.component.spec.ts │ │ │ │ │ └── under-development.component.ts │ │ │ │ └── video-player │ │ │ │ │ ├── video-player.component.html │ │ │ │ │ ├── video-player.component.scss │ │ │ │ │ └── video-player.component.ts │ │ │ ├── login │ │ │ │ ├── auth │ │ │ │ │ ├── auth.component.html │ │ │ │ │ ├── auth.component.scss │ │ │ │ │ ├── auth.component.spec.ts │ │ │ │ │ └── auth.component.ts │ │ │ │ ├── login-routing.module.ts │ │ │ │ ├── login.component.css │ │ │ │ ├── login.component.html │ │ │ │ ├── login.component.spec.ts │ │ │ │ ├── login.component.ts │ │ │ │ └── login.module.ts │ │ │ ├── modules │ │ │ │ ├── abstracte │ │ │ │ │ ├── abstracte-routing.module.ts │ │ │ │ │ ├── abstracte.const.ts │ │ │ │ │ ├── abstracte.module.ts │ │ │ │ │ ├── edit-abstracte-form │ │ │ │ │ │ ├── edit-abstracte-form.component.html │ │ │ │ │ │ ├── edit-abstracte-form.component.scss │ │ │ │ │ │ ├── edit-abstracte-form.component.spec.ts │ │ │ │ │ │ └── edit-abstracte-form.component.ts │ │ │ │ │ ├── edit-abstracte-page │ │ │ │ │ │ ├── edit-abstracte-page.component.html │ │ │ │ │ │ ├── edit-abstracte-page.component.scss │ │ │ │ │ │ ├── edit-abstracte-page.component.spec.ts │ │ │ │ │ │ └── edit-abstracte-page.component.ts │ │ │ │ │ ├── list-abstracte-page │ │ │ │ │ │ ├── list-abstracte-page.component.html │ │ │ │ │ │ ├── list-abstracte-page.component.scss │ │ │ │ │ │ ├── list-abstracte-page.component.spec.ts │ │ │ │ │ │ └── list-abstracte-page.component.ts │ │ │ │ │ └── view-abstracte-page │ │ │ │ │ │ ├── view-abstracte-page.component.html │ │ │ │ │ │ ├── view-abstracte-page.component.scss │ │ │ │ │ │ └── view-abstracte-page.component.ts │ │ │ │ ├── certificate │ │ │ │ │ ├── certificate.module.ts │ │ │ │ │ └── certificate │ │ │ │ │ │ ├── certificate.component.html │ │ │ │ │ │ ├── certificate.component.scss │ │ │ │ │ │ └── certificate.component.ts │ │ │ │ ├── compose-video-player │ │ │ │ │ ├── compose-video-player.component.html │ │ │ │ │ ├── compose-video-player.component.scss │ │ │ │ │ ├── compose-video-player.component.spec.ts │ │ │ │ │ └── compose-video-player.component.ts │ │ │ │ ├── overview │ │ │ │ │ ├── info │ │ │ │ │ │ ├── info.component.html │ │ │ │ │ │ ├── info.component.scss │ │ │ │ │ │ ├── info.component.spec.ts │ │ │ │ │ │ └── info.component.ts │ │ │ │ │ ├── metrics │ │ │ │ │ │ ├── metrics.component.html │ │ │ │ │ │ ├── metrics.component.scss │ │ │ │ │ │ ├── metrics.component.spec.ts │ │ │ │ │ │ └── metrics.component.ts │ │ │ │ │ ├── overview-routing.module.ts │ │ │ │ │ ├── overview.component.html │ │ │ │ │ ├── overview.component.scss │ │ │ │ │ ├── overview.component.spec.ts │ │ │ │ │ ├── overview.component.ts │ │ │ │ │ └── overview.module.ts │ │ │ │ ├── payment │ │ │ │ │ ├── pay-form │ │ │ │ │ │ ├── pay-form.component.html │ │ │ │ │ │ ├── pay-form.component.scss │ │ │ │ │ │ └── pay-form.component.ts │ │ │ │ │ ├── pay.service.spec.ts │ │ │ │ │ ├── pay.service.ts │ │ │ │ │ └── payment.module.ts │ │ │ │ ├── questions │ │ │ │ │ ├── file-extension.pipe.ts │ │ │ │ │ ├── list-questions-page │ │ │ │ │ │ ├── list-questions-page.component.html │ │ │ │ │ │ ├── list-questions-page.component.scss │ │ │ │ │ │ ├── list-questions-page.component.spec.ts │ │ │ │ │ │ └── list-questions-page.component.ts │ │ │ │ │ ├── only-with-anaswer.pipe.ts │ │ │ │ │ ├── question-form │ │ │ │ │ │ ├── question-form.component.html │ │ │ │ │ │ ├── question-form.component.scss │ │ │ │ │ │ ├── question-form.component.spec.ts │ │ │ │ │ │ └── question-form.component.ts │ │ │ │ │ ├── question-rules │ │ │ │ │ │ ├── question-rules.component.html │ │ │ │ │ │ ├── question-rules.component.scss │ │ │ │ │ │ ├── question-rules.component.spec.ts │ │ │ │ │ │ └── question-rules.component.ts │ │ │ │ │ ├── question-view │ │ │ │ │ │ ├── question-view.component.html │ │ │ │ │ │ ├── question-view.component.scss │ │ │ │ │ │ ├── question-view.component.spec.ts │ │ │ │ │ │ └── question-view.component.ts │ │ │ │ │ ├── questions.const.ts │ │ │ │ │ ├── questions.module.ts │ │ │ │ │ ├── questions.routing.module.ts │ │ │ │ │ └── yt-from-url.pipe.ts │ │ │ │ ├── roadmap │ │ │ │ │ ├── roadmap.component.html │ │ │ │ │ ├── roadmap.component.scss │ │ │ │ │ ├── roadmap.component.spec.ts │ │ │ │ │ └── roadmap.component.ts │ │ │ │ ├── streams │ │ │ │ │ ├── streams.component.html │ │ │ │ │ ├── streams.component.scss │ │ │ │ │ ├── streams.component.spec.ts │ │ │ │ │ └── streams.component.ts │ │ │ │ └── targets │ │ │ │ │ ├── calc-progress.pipe.spec.ts │ │ │ │ │ ├── calc-progress.pipe.ts │ │ │ │ │ ├── count-closed-tasks.pipe.ts │ │ │ │ │ ├── count-open-tasks.pipe.ts │ │ │ │ │ ├── list-aims-page │ │ │ │ │ ├── list-aims-page.component.html │ │ │ │ │ ├── list-aims-page.component.scss │ │ │ │ │ ├── list-aims-page.component.spec.ts │ │ │ │ │ └── list-aims-page.component.ts │ │ │ │ │ ├── list-targets-page │ │ │ │ │ ├── list-targets-page.component.html │ │ │ │ │ ├── list-targets-page.component.scss │ │ │ │ │ ├── list-targets-page.component.spec.ts │ │ │ │ │ └── list-targets-page.component.ts │ │ │ │ │ ├── list-templates-page │ │ │ │ │ ├── list-templates-page.component.html │ │ │ │ │ ├── list-templates-page.component.scss │ │ │ │ │ ├── list-templates-page.component.spec.ts │ │ │ │ │ └── list-templates-page.component.ts │ │ │ │ │ ├── progress.helper.ts │ │ │ │ │ ├── target-edit-form │ │ │ │ │ ├── target-edit-form.component.html │ │ │ │ │ ├── target-edit-form.component.scss │ │ │ │ │ ├── target-edit-form.component.spec.ts │ │ │ │ │ └── target-edit-form.component.ts │ │ │ │ │ ├── targets-routing.module.ts │ │ │ │ │ ├── targets.const.ts │ │ │ │ │ ├── targets.helpers.ts │ │ │ │ │ ├── targets.module.ts │ │ │ │ │ ├── task-edit-form │ │ │ │ │ ├── task-edit-form.component.html │ │ │ │ │ ├── task-edit-form.component.scss │ │ │ │ │ ├── task-edit-form.component.spec.ts │ │ │ │ │ └── task-edit-form.component.ts │ │ │ │ │ ├── task-tree-edit-form │ │ │ │ │ ├── task-tree-edit-form.component.html │ │ │ │ │ ├── task-tree-edit-form.component.scss │ │ │ │ │ ├── task-tree-edit-form.component.spec.ts │ │ │ │ │ └── task-tree-edit-form.component.ts │ │ │ │ │ └── template-create │ │ │ │ │ ├── template-create.component.html │ │ │ │ │ ├── template-create.component.scss │ │ │ │ │ ├── template-create.component.spec.ts │ │ │ │ │ └── template-create.component.ts │ │ │ ├── pages-routing.module.ts │ │ │ ├── pages.module.ts │ │ │ ├── router-compose │ │ │ │ ├── compose-icontabs-page │ │ │ │ │ ├── compose-icontabs-page.component.html │ │ │ │ │ ├── compose-icontabs-page.component.scss │ │ │ │ │ ├── compose-icontabs-page.component.spec.ts │ │ │ │ │ └── compose-icontabs-page.component.ts │ │ │ │ ├── compose-one-page │ │ │ │ │ ├── compose-one-page.component.html │ │ │ │ │ ├── compose-one-page.component.scss │ │ │ │ │ ├── compose-one-page.component.spec.ts │ │ │ │ │ └── compose-one-page.component.ts │ │ │ │ ├── compose-page.ts │ │ │ │ ├── compose-tab-page │ │ │ │ │ ├── compose-tab-page.component.html │ │ │ │ │ ├── compose-tab-page.component.scss │ │ │ │ │ ├── compose-tab-page.component.spec.ts │ │ │ │ │ └── compose-tab-page.component.ts │ │ │ │ └── router-compose.module.ts │ │ │ └── soer-components │ │ │ │ ├── soer-components.module.ts │ │ │ │ └── topics-list │ │ │ │ ├── topics-list.component.html │ │ │ │ ├── topics-list.component.scss │ │ │ │ ├── topics-list.component.spec.ts │ │ │ │ └── topics-list.component.ts │ │ └── services │ │ │ ├── application.models.ts │ │ │ ├── application.service.spec.ts │ │ │ ├── application.service.ts │ │ │ └── menu │ │ │ ├── MenuControl.class.ts │ │ │ ├── menu.const.ts │ │ │ └── menu.interfaces.ts │ ├── assets │ │ ├── .gitkeep │ │ ├── favicons │ │ │ ├── android-chrome-144x144.png │ │ │ ├── android-chrome-192x192.png │ │ │ ├── android-chrome-256x256.png │ │ │ ├── android-chrome-36x36.png │ │ │ ├── android-chrome-384x384.png │ │ │ ├── android-chrome-48x48.png │ │ │ ├── android-chrome-512x512.png │ │ │ ├── android-chrome-72x72.png │ │ │ ├── android-chrome-96x96.png │ │ │ ├── apple-touch-icon-precomposed.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-194x194.png │ │ │ ├── favicon-32x32.png │ │ │ ├── mstile-144x144.png │ │ │ ├── mstile-150x150.png │ │ │ ├── mstile-310x150.png │ │ │ ├── mstile-310x310.png │ │ │ ├── mstile-70x70.png │ │ │ └── safari-pinned-tab.svg │ │ ├── logo3.svg │ │ ├── logo3.svg.2021_04_13_21_56_03.0.svg │ │ └── soerpro.svg │ ├── environments │ │ ├── constants.ts │ │ ├── environment.interface.ts │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── icons-provider.module.ts │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.scss │ └── test-setup.ts │ ├── tsconfig.app.json │ ├── tsconfig.editor.json │ ├── tsconfig.json │ └── tsconfig.spec.json ├── build.sh ├── decorate-angular-cli.js ├── jest.config.js ├── jest.preset.js ├── libs ├── .gitkeep ├── mixed-bus │ ├── .browserslistrc │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.js │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── interfaces │ │ │ │ └── mixed-bus.interface.ts │ │ │ ├── mixed-bus.helpers.ts │ │ │ ├── mixed-bus.module.ts │ │ │ ├── mixed-bus.service.spec.ts │ │ │ └── mixed-bus.service.ts │ │ └── test-setup.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── sr-auth │ ├── .browserslistrc │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.js │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── auth.helpers.ts │ │ │ ├── guards │ │ │ │ └── auth.guard.ts │ │ │ ├── interceptors │ │ │ │ └── auth-interceptor.interceptor.ts │ │ │ ├── interfaces │ │ │ │ ├── auth-options.interface.ts │ │ │ │ └── jwt.models.ts │ │ │ ├── services │ │ │ │ └── auth.service.ts │ │ │ └── sr-auth.module.ts │ │ └── test-setup.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── sr-dto │ ├── .browserslistrc │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.js │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── bus-messages │ │ │ │ └── bus.messages.ts │ │ │ ├── dto.helpers.ts │ │ │ ├── dto.pipes.ts │ │ │ ├── interfaces │ │ │ │ ├── crud.interface.ts │ │ │ │ ├── dto.pack.interface.ts │ │ │ │ └── serialize-json.model.ts │ │ │ ├── services │ │ │ │ ├── data-store.service.ts │ │ │ │ ├── resolve-read-emitter.service.ts │ │ │ │ └── store.crud.service.ts │ │ │ └── sr-dto.module.ts │ │ └── test-setup.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── sr-editor │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.ts │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── blocks │ │ │ │ ├── block-editor │ │ │ │ │ ├── block-editor.component.html │ │ │ │ │ ├── block-editor.component.scss │ │ │ │ │ ├── block-editor.component.spec.ts │ │ │ │ │ └── block-editor.component.ts │ │ │ │ └── block-test │ │ │ │ │ ├── block-test.component.html │ │ │ │ │ ├── block-test.component.scss │ │ │ │ │ ├── block-test.component.spec.ts │ │ │ │ │ └── block-test.component.ts │ │ │ ├── editor │ │ │ │ ├── editor.component.html │ │ │ │ ├── editor.component.scss │ │ │ │ ├── editor.component.spec.ts │ │ │ │ └── editor.component.ts │ │ │ ├── interfaces │ │ │ │ └── document.model.ts │ │ │ ├── sr-editor.module.ts │ │ │ └── textarea-autoresize.directive.ts │ │ └── test-setup.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json └── sr-url-builder │ ├── .browserslistrc │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.js │ ├── src │ ├── index.ts │ ├── lib │ │ ├── interfaces │ │ │ └── url-builder.interface.ts │ │ ├── services │ │ │ └── url-builder.service.ts │ │ └── sr-url-builder.module.ts │ └── test-setup.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── migrations.json ├── nx.json ├── package-lock.json ├── package.json ├── publish.sh ├── tools ├── generators │ └── .gitkeep └── tsconfig.tools.json ├── tsconfig.base.json └── workshop └── rest ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── README.md ├── nest-cli.json ├── package-lock.json ├── package.json ├── src ├── app.controller.spec.ts ├── app.controller.ts ├── app.module.ts ├── app.service.ts ├── documents │ ├── documents.api.http │ ├── documents.controller.spec.ts │ ├── documents.controller.ts │ ├── documents.module.ts │ ├── documents.service.ts │ ├── dto │ │ ├── create-document.dto.ts │ │ └── update-document.dto.ts │ └── entities │ │ └── document.entity.ts ├── groups │ ├── dto │ │ ├── create-group.dto.ts │ │ └── update-group.dto.ts │ ├── entities │ │ └── group.entity.ts │ ├── groups.api.http │ ├── groups.controller.spec.ts │ ├── groups.controller.ts │ ├── groups.module.ts │ └── groups.service.ts └── main.ts ├── test ├── app.e2e-spec.ts └── jest-e2e.json ├── tsconfig.build.json └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": ["**/*"], 4 | "plugins": ["@nrwl/nx"], 5 | "overrides": [ 6 | { 7 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 8 | "rules": { 9 | "@nrwl/nx/enforce-module-boundaries": [ 10 | "error", 11 | { 12 | "enforceBuildableLibDependency": true, 13 | "allow": [], 14 | "depConstraints": [ 15 | { 16 | "sourceTag": "*", 17 | "onlyDependOnLibsWithTags": ["*"] 18 | } 19 | ] 20 | } 21 | ] 22 | } 23 | }, 24 | { 25 | "files": ["*.ts", "*.tsx"], 26 | "extends": ["plugin:@nrwl/nx/typescript"], 27 | "rules": {} 28 | }, 29 | { 30 | "files": ["*.js", "*.jsx"], 31 | "extends": ["plugin:@nrwl/nx/javascript"], 32 | "rules": {} 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | 41 | .angular 42 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v14.18.2 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Add files here to ignore them from prettier formatting 2 | 3 | /dist 4 | /coverage 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "angular.ng-template", 4 | "nrwl.angular-console", 5 | "esbenp.prettier-vscode", 6 | "firsttris.vscode-jest-runner", 7 | "dbaeumer.vscode-eslint" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Монорепозиторий Soer Open Source 4 | 5 | This project was generated using [Nx](https://nx.dev). 6 | 7 | Репозиторий создан для организации совместной разработки участников проекта soer.pro 8 | 9 | # Install 10 | 11 | ``` 12 | Fork repository 13 | git clone git@github.com:/soer.git 14 | cd soer 15 | nvm use 16 | npm install 17 | npx nx serve naris 18 | ``` 19 | 20 | # Login 21 | 22 | - Открыть браузер http://localhost:4200 23 | - Выбрать один из доступных методов авторизации 24 | - Подождать несколько секунд, нажать кнопку "Режим разработчика" 25 | 26 | # Проекты 27 | 28 | ## Naris 29 | 30 | Naris - это платформа для саморазвития, которая включает в себя следующие возможности: 31 | 32 | - Раздельный доступ к материалам на основе ролей; 33 | - Брифинг текущих задач; 34 | - Постановка целей; 35 | - Публикация заметок; 36 | - Секция "Вопрос/ответ"; 37 | - Видео-материалы; 38 | - Архив материалов для скачивания. 39 | 40 | Проект разделен на две части - фронтенд и бэкенд. На данный момент в репозитории размещена только фронтенд часть. 41 | -------------------------------------------------------------------------------- /apps/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/.gitkeep -------------------------------------------------------------------------------- /apps/naris-e2e/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:cypress/recommended", "../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["src/plugins/index.js"], 11 | "rules": { 12 | "@typescript-eslint/no-var-requires": "off", 13 | "no-undef": "off" 14 | } 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /apps/naris-e2e/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileServerFolder": ".", 3 | "fixturesFolder": "./src/fixtures", 4 | "integrationFolder": "./src/integration", 5 | "modifyObstructiveCode": false, 6 | "supportFile": "./src/support/index.ts", 7 | "pluginsFile": false, 8 | "video": true, 9 | "videosFolder": "../../dist/cypress/apps/naris-e2e/videos", 10 | "screenshotsFolder": "../../dist/cypress/apps/naris-e2e/screenshots", 11 | "chromeWebSecurity": false 12 | } 13 | -------------------------------------------------------------------------------- /apps/naris-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /apps/naris-e2e/src/integration/app.spec.ts: -------------------------------------------------------------------------------- 1 | import { getGreeting } from '../support/app.po'; 2 | 3 | describe('naris', () => { 4 | beforeEach(() => cy.visit('/')); 5 | 6 | it('should display welcome message', () => { 7 | // Custom command example, see `../support/commands.ts` file 8 | cy.login('my-email@something.com', 'myPassword'); 9 | 10 | // Function helper example, see `../support/app.po.ts` file 11 | getGreeting().contains('Welcome naris'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /apps/naris-e2e/src/support/app.po.ts: -------------------------------------------------------------------------------- 1 | export const getGreeting = () => cy.get('h1'); 2 | -------------------------------------------------------------------------------- /apps/naris-e2e/src/support/commands.ts: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | 11 | // eslint-disable-next-line @typescript-eslint/no-namespace 12 | declare namespace Cypress { 13 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 14 | interface Chainable { 15 | login(email: string, password: string): void; 16 | } 17 | } 18 | // 19 | // -- This is a parent command -- 20 | Cypress.Commands.add('login', (email, password) => { 21 | console.log('Custom command example: Login', email, password); 22 | }); 23 | // 24 | // -- This is a child command -- 25 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 26 | // 27 | // 28 | // -- This is a dual command -- 29 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 30 | // 31 | // 32 | // -- This will overwrite an existing command -- 33 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 34 | -------------------------------------------------------------------------------- /apps/naris-e2e/src/support/index.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands'; 18 | -------------------------------------------------------------------------------- /apps/naris-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "sourceMap": false, 5 | "outDir": "../../dist/out-tsc", 6 | "allowJs": true, 7 | "types": ["cypress", "node"], 8 | "forceConsistentCasingInFileNames": true, 9 | "strict": true, 10 | "noImplicitOverride": true, 11 | "noPropertyAccessFromIndexSignature": true, 12 | "noImplicitReturns": true, 13 | "noFallthroughCasesInSwitch": true 14 | }, 15 | "include": ["src/**/*.ts", "src/**/*.js"], 16 | "angularCompilerOptions": { 17 | "strictInjectionParameters": true, 18 | "strictInputAccessModifiers": true, 19 | "strictTemplates": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /apps/naris/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | -------------------------------------------------------------------------------- /apps/naris/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@nrwl/nx/angular", 9 | "plugin:@angular-eslint/template/process-inline-templates" 10 | ], 11 | "rules": { 12 | "@angular-eslint/directive-selector": [ 13 | "error", 14 | { 15 | "type": "attribute", 16 | "prefix": "soer", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "soer", 25 | "style": "kebab-case" 26 | } 27 | ] 28 | } 29 | }, 30 | { 31 | "files": ["*.html"], 32 | "extends": ["plugin:@nrwl/nx/angular-template"], 33 | "rules": {} 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /apps/naris/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'naris', 3 | preset: '../../jest.preset.js', 4 | setupFilesAfterEnv: ['/src/test-setup.ts'], 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | stringifyContentPathRegex: '\\.(html|svg)$', 9 | }, 10 | }, 11 | coverageDirectory: '../../coverage/apps/naris', 12 | transform: { 13 | '^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular', 14 | }, 15 | transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], 16 | snapshotSerializers: [ 17 | 'jest-preset-angular/build/serializers/no-ng-attributes', 18 | 'jest-preset-angular/build/serializers/ng-snapshot', 19 | 'jest-preset-angular/build/serializers/html-comment', 20 | ], 21 | }; 22 | -------------------------------------------------------------------------------- /apps/naris/src/app/api/by-route-path.resolver.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient, HttpHandler } from '@angular/common/http'; 2 | import { TestBed } from '@angular/core/testing'; 3 | 4 | import { ByRoutePathResolver } from './by-route-path.resolver'; 5 | 6 | describe('ByRoutePathResolver', () => { 7 | let resolver: ByRoutePathResolver; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | providers: [ 12 | HttpClient, 13 | HttpHandler, 14 | ByRoutePathResolver 15 | ] 16 | }); 17 | resolver = TestBed.inject(ByRoutePathResolver); 18 | }); 19 | 20 | it('should be created', () => { 21 | expect(resolver).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /apps/naris/src/app/api/by-route-path.resolver.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { 4 | Resolve, 5 | RouterStateSnapshot, 6 | ActivatedRouteSnapshot 7 | } from '@angular/router'; 8 | import { Observable } from 'rxjs'; 9 | import { environment } from '../../environments/environment'; 10 | 11 | @Injectable() 12 | export class ByRoutePathResolver implements Resolve { 13 | constructor(private http: HttpClient) {} 14 | resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { 15 | const path = route.routeConfig?.path || 'overview'; 16 | return this.http.get(`${environment.assetsUrl}${path}.json`); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /apps/naris/src/app/api/jsonDto.model.ts: -------------------------------------------------------------------------------- 1 | export interface JsonDTOModel { 2 | id?: number; 3 | json: string; 4 | } -------------------------------------------------------------------------------- /apps/naris/src/app/api/progress/events/watch-video.event.ts: -------------------------------------------------------------------------------- 1 | import { ANY_SERVICE, BusEmitter, BusEvent } from "@soer/mixed-bus"; 2 | import { VideoIdModel } from "../personal-activity.service"; 3 | 4 | export class WatchVideoEvent extends BusEvent { 5 | constructor( 6 | public override owner: BusEmitter = ANY_SERVICE, 7 | public video: VideoIdModel 8 | ) { 9 | super(owner, video) 10 | } 11 | } -------------------------------------------------------------------------------- /apps/naris/src/app/api/progress/progress.const.ts: -------------------------------------------------------------------------------- 1 | import { BusKey } from "@soer/mixed-bus"; 2 | 3 | export interface ActivityKey extends BusKey { 4 | aid: string; 5 | } -------------------------------------------------------------------------------- /apps/naris/src/app/api/questions/question.model.ts: -------------------------------------------------------------------------------- 1 | export interface QuestionModel { 2 | id?: number; 3 | question: string; 4 | url?: string; 5 | createdAt?: Date; 6 | updatedAt?: Date; 7 | } 8 | 9 | -------------------------------------------------------------------------------- /apps/naris/src/app/api/streams/stream.model.ts: -------------------------------------------------------------------------------- 1 | export interface VideoModel { 2 | vimeo_id?: string; 3 | youtube_id?: string; 4 | thumb_url?: string; 5 | title: string; 6 | desc: string; 7 | children?: VideoModel[]; 8 | 9 | } -------------------------------------------------------------------------------- /apps/naris/src/app/api/streams/stream.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient, HttpHandler } from '@angular/common/http'; 2 | import { TestBed } from '@angular/core/testing'; 3 | 4 | import { StreamService } from './stream.service'; 5 | 6 | describe('StreamService', () => { 7 | let service: StreamService; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | providers: [ 12 | HttpClient, 13 | HttpHandler, 14 | StreamService 15 | 16 | ] 17 | }); 18 | service = TestBed.inject(StreamService); 19 | }); 20 | 21 | it('should be created', () => { 22 | expect(service).toBeTruthy(); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /apps/naris/src/app/api/streams/stream.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Resolve } from '@angular/router'; 4 | import { Observable } from 'rxjs'; 5 | import { environment } from '../../../environments/environment'; 6 | import { VideoModel } from './stream.model'; 7 | 8 | @Injectable() 9 | export class StreamService implements Resolve{ 10 | 11 | constructor(private http: HttpClient) {} 12 | 13 | 14 | getStreams(): Observable { 15 | return this.http.get(environment.assetsUrl + 'streams.json'); 16 | } 17 | resolve(): Observable { 18 | return this.getStreams(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /apps/naris/src/app/api/targets/target.interface.ts: -------------------------------------------------------------------------------- 1 | export interface PersonalTarget { 2 | id?: number; 3 | title: string; 4 | overview: string; 5 | activity: string; 6 | tasks: RoadmapTask[]; 7 | } 8 | 9 | export interface TargetModel { 10 | id?: number; 11 | title: string; 12 | overview: string; 13 | progress: number; 14 | tasks: TargetModel[]; 15 | } 16 | 17 | export interface TemplateModel { 18 | id?: number; 19 | title: string; 20 | overview: string; 21 | progress: number; 22 | tasks: TemplateModel[]; 23 | } 24 | export interface RoadmapTask { 25 | title: string; 26 | progress: number; 27 | file?: string; 28 | children: RoadmapTask[]; 29 | } 30 | 31 | export const EmptyTarget: TargetModel = { 32 | id: -1, 33 | title: '', 34 | overview: '', 35 | progress: 0, 36 | tasks: [] 37 | } 38 | 39 | export interface Visibility { 40 | [id: string]: boolean; 41 | } -------------------------------------------------------------------------------- /apps/naris/src/app/api/tasks/tasks.resolver.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient, HttpHandler } from '@angular/common/http'; 2 | import { TestBed } from '@angular/core/testing'; 3 | 4 | import { TasksResolver } from './tasks.resolver'; 5 | 6 | describe('TasksResolver', () => { 7 | let resolver: TasksResolver; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | providers: [ 12 | HttpClient, 13 | HttpHandler 14 | ] 15 | }); 16 | resolver = TestBed.inject(TasksResolver); 17 | }); 18 | 19 | it('should be created', () => { 20 | expect(resolver).toBeTruthy(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /apps/naris/src/app/api/tasks/tasks.resolver.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { 4 | Resolve, 5 | RouterStateSnapshot, 6 | ActivatedRouteSnapshot 7 | } from '@angular/router'; 8 | import { Observable, of } from 'rxjs'; 9 | 10 | @Injectable({ 11 | providedIn: 'root' 12 | }) 13 | export class TasksResolver implements Resolve { 14 | constructor(private http: HttpClient) {} 15 | 16 | getTasks(): Observable { 17 | return this.http.get('http://localhost:3001/assets/tasks.json'); 18 | } 19 | resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { 20 | return this.getTasks(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /apps/naris/src/app/api/workbook/workbook.model.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/app/api/workbook/workbook.model.ts -------------------------------------------------------------------------------- /apps/naris/src/app/api/workshops/workshops.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router'; 4 | import { Observable } from 'rxjs'; 5 | import { environment } from '../../../environments/environment'; 6 | 7 | @Injectable() 8 | export class WorkshopsService implements Resolve{ 9 | 10 | constructor(private http: HttpClient) {} 11 | 12 | 13 | getWorkshops(): Observable { 14 | return this.http.get(environment.assetsUrl + 'workshops.json'); 15 | } 16 | resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { 17 | return this.getWorkshops(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /apps/naris/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/naris/src/app/app.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/app/app.component.scss -------------------------------------------------------------------------------- /apps/naris/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | import { NxWelcomeComponent } from './nx-welcome.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async () => { 7 | await TestBed.configureTestingModule({ 8 | declarations: [AppComponent, NxWelcomeComponent], 9 | }).compileComponents(); 10 | }); 11 | 12 | it('should create the app', () => { 13 | const fixture = TestBed.createComponent(AppComponent); 14 | const app = fixture.componentInstance; 15 | expect(app).toBeTruthy(); 16 | }); 17 | 18 | it(`should have as title 'naris'`, () => { 19 | const fixture = TestBed.createComponent(AppComponent); 20 | const app = fixture.componentInstance; 21 | expect(app.title).toEqual('naris'); 22 | }); 23 | 24 | it('should render title', () => { 25 | const fixture = TestBed.createComponent(AppComponent); 26 | fixture.detectChanges(); 27 | const compiled = fixture.nativeElement as HTMLElement; 28 | expect(compiled.querySelector('router-outlet')).toBeTruthy; 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /apps/naris/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'soer-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.scss'], 7 | }) 8 | export class AppComponent { 9 | title = 'naris'; 10 | } 11 | -------------------------------------------------------------------------------- /apps/naris/src/app/nx-welcome.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewEncapsulation } from '@angular/core'; 2 | import { MixedBusService } from '@soer/mixed-bus'; 3 | 4 | @Component({ 5 | selector: 'soer-nx-welcome', 6 | template: ` 7 | 8 | Welcome naris 9 | 10 |

Welcome naris

11 | 12 | 13 | `, 14 | encapsulation: ViewEncapsulation.None, 15 | }) 16 | export class NxWelcomeComponent { 17 | constructor(public mixedBus: MixedBusService) {} 18 | } 19 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/components/files-list/files-list.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 |
15 |
16 | 17 |

{{file['desc']}}

18 |
19 | {{file['level']}} 20 | {{label}} 21 |
22 | 23 |
24 | 25 |
26 |
27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | скачать 36 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/components/files-list/files-list.component.scss: -------------------------------------------------------------------------------- 1 | .files-card { 2 | &, 3 | &-link, 4 | ::ng-deep.ant-card-meta, 5 | ::ng-deep.ant-card-meta-detail, 6 | ::ng-deep.ant-card-meta-description { 7 | display: flex; 8 | flex-direction: column; 9 | height: 100%; 10 | } 11 | 12 | &_desc, 13 | ::ng-deep.ant-card-body { 14 | flex-grow: 1; 15 | } 16 | 17 | ::ng-deep.ant-card-meta-title { 18 | margin-bottom: 0; 19 | padding-bottom: 8px; 20 | } 21 | } 22 | 23 | .file-icon { 24 | width: 100%; 25 | font-size: 5em; 26 | text-align: center; 27 | } 28 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/components/files-list/files-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpClientTestingModule } from '@angular/common/http/testing'; 2 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { RouterTestingModule } from '@angular/router/testing'; 4 | import { NzMessageService } from 'ng-zorro-antd/message'; 5 | 6 | import { FilesListComponent } from './files-list.component'; 7 | class MockNzMessageService { 8 | 9 | } 10 | 11 | describe('FilesListComponent', () => { 12 | let component: FilesListComponent; 13 | let fixture: ComponentFixture; 14 | 15 | beforeEach(async () => { 16 | await TestBed.configureTestingModule({ 17 | declarations: [ FilesListComponent ], 18 | imports: [ 19 | HttpClientTestingModule, 20 | RouterTestingModule 21 | ], 22 | providers: [ 23 | { provide: NzMessageService, useClass: MockNzMessageService} 24 | ] 25 | }) 26 | .compileComponents(); 27 | }); 28 | 29 | beforeEach(() => { 30 | fixture = TestBed.createComponent(FilesListComponent); 31 | component = fixture.componentInstance; 32 | fixture.detectChanges(); 33 | }); 34 | 35 | it('should create', () => { 36 | expect(component).toBeTruthy(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/components/files-list/files-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | import { environment } from '../../../../environments/environment'; 4 | import { NzMessageService } from 'ng-zorro-antd/message'; 5 | 6 | @Component({ 7 | selector: 'soer-files-list', 8 | templateUrl: './files-list.component.html', 9 | styleUrls: ['./files-list.component.scss'] 10 | }) 11 | export class FilesListComponent implements OnInit { 12 | 13 | webFiles = []; 14 | 15 | 16 | constructor(private route: ActivatedRoute, 17 | private message: NzMessageService 18 | ) { } 19 | 20 | ngOnInit(): void { 21 | this.webFiles = this.route.snapshot.data['webfiles']; 22 | } 23 | 24 | url(file: string, level: string): string { 25 | if (file.match(/^http[s]?:/)) { 26 | return file; 27 | } 28 | return `${environment.assetsUrl}${level}/${file}`; 29 | } 30 | 31 | download(event: any, file: any): void { 32 | if(file.icon === 'lock') { 33 | this.message.error(`Для скачивания этого файла нужен уровень ${file.level.toUpperCase()}`); 34 | event.preventDefault(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/default/default.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { 3 | HttpClientTestingModule 4 | } from '@angular/common/http/testing'; 5 | import { DefaultComponent } from './default.component'; 6 | import {RouterTestingModule} from "@angular/router/testing"; 7 | import { NzMessageService } from 'ng-zorro-antd/message'; 8 | import { SrDTOModule } from '@soer/sr-dto'; 9 | import { ANY_SERVICE } from '@soer/mixed-bus'; 10 | 11 | class MockNzMessageService { 12 | 13 | } 14 | describe('DefaultComponent', () => { 15 | let component: DefaultComponent; 16 | let fixture: ComponentFixture; 17 | 18 | beforeEach(async () => { 19 | await TestBed.configureTestingModule({ 20 | declarations: [ DefaultComponent ], 21 | imports: [ 22 | HttpClientTestingModule, 23 | RouterTestingModule, 24 | SrDTOModule 25 | ], 26 | providers: [ 27 | {provide: 'manifest', useValue: ANY_SERVICE}, 28 | {provide: 'issues', useValue: ANY_SERVICE}, 29 | {provide: 'AuthService', useValue: {}}, 30 | {provide: 'AuthServiceConfig', useValue: {}}, 31 | {provide: NzMessageService, useClass: MockNzMessageService} 32 | ] 33 | }) 34 | .compileComponents(); 35 | }); 36 | 37 | beforeEach(() => { 38 | fixture = TestBed.createComponent(DefaultComponent); 39 | component = fixture.componentInstance; 40 | fixture.detectChanges(); 41 | }); 42 | 43 | it('should create', () => { 44 | expect(component).toBeTruthy(); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/default/menu.const.ts: -------------------------------------------------------------------------------- 1 | import { IMenuControl } from "../../services/menu/menu.interfaces"; 2 | 3 | export interface MenuItem { 4 | title: string; 5 | icon: string; 6 | link?: string; 7 | isPro: boolean; 8 | children?: MenuItem[]; 9 | } 10 | export const MAIN_MENU: MenuItem[] = [ 11 | { link: 'overview', icon: 'rocket', title: 'Брифинг', isPro: false }, 12 | { 13 | icon: 'appstore', title: 'Развитие', children: [ 14 | { link: 'targets', icon: 'check-circle', title: 'Цели', isPro: false }, 15 | { link: 'workbook', icon: 'solution', title: 'Конспекты', isPro: false }, 16 | { link: 'qa', icon: 'question', title: 'Вопрос ответ', isPro: false }, 17 | ], isPro: false 18 | }, 19 | { 20 | icon: 'play-circle', title: 'Материалы', children: [ 21 | { link: 'streams', icon: 'play-circle', title: 'Стримы', isPro: true }, 22 | { link: 'workshops', icon: 'experiment', title: 'Воркшопы', isPro: true }, 23 | { link: 'book', icon: 'book', title: 'Книга (главы)', isPro: true }, 24 | ], isPro: false 25 | }, 26 | { link: 'sources', icon: 'book', title: 'Исходники', isPro: true } 27 | ]; 28 | 29 | 30 | export interface ISubMenuControls { 31 | controls(): IMenuControl[]; 32 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/default/mobile-menu/mobile-menu.component.scss: -------------------------------------------------------------------------------- 1 | .menu-container { 2 | display: flex; 3 | flex-direction: row; 4 | justify-content: space-between; 5 | } 6 | 7 | .mobile-menu { 8 | z-index: 500; 9 | position: fixed; 10 | left:0; 11 | right:0; 12 | bottom:0; 13 | background-color: rgba(255,255,255,0.9); 14 | padding: 5px; 15 | } 16 | 17 | .desktop-menu { 18 | z-index: 500; 19 | position: fixed; 20 | right:25px; 21 | bottom:25px; 22 | padding: 2px 0 2px 1em; 23 | border-radius: 5%; 24 | box-shadow: 0 0 2px rgb(147 151 173 / 10%), 0px 2px 5px 2px rgb(147 151 173 / 30%); 25 | background-color:rgba($color: #fff, $alpha: 0.3); 26 | } 27 | 28 | .main-menu { 29 | flex-grow: 0; 30 | } 31 | 32 | .controls { 33 | display: flex; 34 | padding-right: 1em; 35 | flex-direction: row; 36 | flex-grow: 1; 37 | justify-content: flex-end; 38 | .control { 39 | margin: 2px; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/default/mobile-menu/mobile-menu.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { NzDropDownModule } from 'ng-zorro-antd/dropdown'; 3 | 4 | import { MobileMenuComponent } from './mobile-menu.component'; 5 | 6 | describe('MobileMenuComponent', () => { 7 | let component: MobileMenuComponent; 8 | let fixture: ComponentFixture; 9 | 10 | beforeEach(async () => { 11 | await TestBed.configureTestingModule({ 12 | declarations: [MobileMenuComponent], 13 | imports: [ 14 | NzDropDownModule 15 | ] 16 | }).compileComponents(); 17 | 18 | fixture = TestBed.createComponent(MobileMenuComponent); 19 | component = fixture.componentInstance; 20 | component.userInfo = {id: 1, role: 'GUEST', email: 'test@test.com'}; 21 | fixture.detectChanges(); 22 | }); 23 | 24 | it('should create', () => { 25 | expect(component).toBeTruthy(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/default/mobile-menu/mobile-menu.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, Input, Output } from '@angular/core'; 2 | import { UserModel } from '../../../services/application.models'; 3 | import { IMenuControl, MenuTree } from '../../../services/menu/menu.interfaces'; 4 | 5 | @Component({ 6 | selector: 'soer-mobile-menu', 7 | templateUrl: './mobile-menu.component.html', 8 | styleUrls: ['./mobile-menu.component.scss'], 9 | }) 10 | export class MobileMenuComponent { 11 | @Input() isMobile = false; 12 | @Input() userInfo: UserModel = {id: -1, role: '', email: ''}; 13 | @Input() applicationMenu: MenuTree = []; 14 | @Input() controls: IMenuControl[] | null = null; 15 | @Output() logout = new EventEmitter(); 16 | @Output() check = new EventEmitter(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/access-denied/access-denied.component.html: -------------------------------------------------------------------------------- 1 |
2 | 7 |
8 |
9 |

10 | 11 | Для доступа к архитектурным стримам - "Stream" 12 |

13 |

14 | 15 | Для доступа к архитектурным стримам и мастерклассам - "Workshop" 16 |

17 |

18 | 19 | Для доступа ко всем материалам и исходным кодам проектов - "PRO" 20 |

21 |
22 |
23 | 26 |
27 |
-------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/access-denied/access-denied.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | margin: auto; 3 | } 4 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/access-denied/access-denied.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AccessDeniedComponent } from './access-denied.component'; 4 | 5 | describe('AccessDeniedComponent', () => { 6 | let component: AccessDeniedComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ AccessDeniedComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(AccessDeniedComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/access-denied/access-denied.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'soer-access-denied', 5 | templateUrl: './access-denied.component.html', 6 | styleUrls: ['./access-denied.component.scss'] 7 | }) 8 | export class AccessDeniedComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/audio-player/audio-player.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/audio-player/audio-player.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/app/pages/dumb/audio-player/audio-player.component.scss -------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/audio-player/audio-player.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AudioPlayerComponent } from './audio-player.component'; 4 | 5 | describe('AudioPlayerComponent', () => { 6 | let component: AudioPlayerComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ AudioPlayerComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(AudioPlayerComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/audio-player/audio-player.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'soer-audio-player', 5 | templateUrl: './audio-player.component.html', 6 | styleUrls: ['./audio-player.component.scss'] 7 | }) 8 | export class AudioPlayerComponent { 9 | 10 | @Input() audioUrl = ''; 11 | 12 | changeSound(event: any, item: any) { 13 | this.audioUrl = ''; 14 | const audioPlayer = document.getElementById('audio'); 15 | if (audioPlayer) { 16 | audioPlayer.load(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/no-content/no-content.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 |
6 | Улучшить уровень 7 | 8 | 9 |
10 |
11 | 12 |
13 |
14 |
15 | 16 |
17 |

Данный контент доступен только на платных подписках.

18 |

Если вы уверены, что доступ должен быть предоставлен напишите письмо на soersoft@gmail.com.

19 |
20 |
-------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/no-content/no-content.component.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | background: #fff; 3 | margin: 0 auto; 4 | width: auto; 5 | position: absolute; 6 | top: 50%; 7 | right: 20px; 8 | left: 20px; 9 | z-index: 1; 10 | cursor: default; 11 | transform: translateY(-50%); 12 | 13 | 14 | 15 | &-width { 16 | max-width: 960px; 17 | } 18 | 19 | .wrapper { 20 | display: block; 21 | box-shadow: 0 1px 2px -2px rgb(0 0 0 / 16%), 0 3px 6px 0 rgb(0 0 0 / 12%), 0 5px 12px 4px rgb(0 0 0 / 9%); 22 | overflow: auto; 23 | } 24 | 25 | .message { 26 | text-align: center; 27 | } 28 | 29 | @media screen and (min-width: 768px) { 30 | .wrapper { 31 | height: 540px; 32 | } 33 | .message { 34 | font-size: 2rem; 35 | } 36 | 37 | 38 | } 39 | 40 | @media screen and (max-width: 768px) { 41 | .wrapper { 42 | height: 320px; 43 | 44 | } 45 | ::ng-deep .ant-result { 46 | padding: 20px 12px; 47 | } 48 | } 49 | } 50 | 51 | ::ng-deep iframe { 52 | width: 100%; 53 | height: 100%; 54 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/no-content/no-content.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute, Router } from '@angular/router'; 3 | 4 | @Component({ 5 | selector: 'soer-no-content', 6 | templateUrl: './no-content.component.html', 7 | styleUrls: ['./no-content.component.scss'] 8 | }) 9 | export class NoContentComponent { 10 | 11 | constructor(private router: Router, private route: ActivatedRoute) {} 12 | 13 | onClose(): void { 14 | const queryParams = this.route.snapshot.queryParams; 15 | this.router.navigate(['.'], {relativeTo: this.route.parent, queryParams}); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/overlay/overlay.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
-------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/overlay/overlay.component.scss: -------------------------------------------------------------------------------- 1 | .overlay { 2 | position: fixed; 3 | top: 0; 4 | right: 0; 5 | bottom: 0; 6 | left: 0; 7 | overflow-y: auto; 8 | 9 | -webkit-transition: opacity ease-in-out .3s; 10 | -moz-transition: opacity ease-in-out .3s; 11 | -o-transition: opacity ease-in-out .3s; 12 | transition: opacity ease-in-out .3s; 13 | 14 | width: 100%; 15 | height: 100%; 16 | 17 | cursor: pointer; 18 | padding: 0 20px; 19 | background-color: rgba(0,0,0,.6); 20 | z-index: 999; 21 | 22 | &-close-icon { 23 | position: absolute; 24 | top: 20px; 25 | right: 20px; 26 | color: white; 27 | font-size: 3em; 28 | z-index: 9999999; 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/overlay/overlay.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { OverlayComponent } from './overlay.component'; 4 | 5 | describe('OverlayComponent', () => { 6 | let component: OverlayComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ OverlayComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(OverlayComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/overlay/overlay.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; 2 | ; 3 | 4 | @Component({ 5 | selector: 'soer-overlay', 6 | templateUrl: './overlay.component.html', 7 | styleUrls: ['./overlay.component.scss'] 8 | }) 9 | export class OverlayComponent { 10 | 11 | @Input() activate = true; 12 | // eslint-disable-next-line @angular-eslint/no-output-native 13 | @Output() readonly close = new EventEmitter(); 14 | 15 | clickOnOverlay(event: any): void { 16 | if (event.target.id === 'overlay') { 17 | this.close.emit(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/sr-text-edit/sr-text-edit.component.scss: -------------------------------------------------------------------------------- 1 | textarea { 2 | width: calc(100% - 4rem); 3 | height: 22px; 4 | padding: 2px 5px; 5 | margin: 5px; 6 | font-size: 14px; 7 | line-height: 16px; 8 | border: 1px solid lightgray; 9 | } 10 | 11 | a { 12 | line-height: 30px; 13 | } 14 | :host * { 15 | vertical-align: middle; 16 | } 17 | :host { 18 | line-height: 30px; 19 | display: flex; 20 | width: 100%; 21 | padding: 0; 22 | margin: 0; 23 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/under-development/under-development.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
-------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/under-development/under-development.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/app/pages/dumb/under-development/under-development.component.scss -------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/under-development/under-development.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { UnderDevelopmentComponent } from './under-development.component'; 4 | 5 | describe('UnderDevelopmentComponent', () => { 6 | let component: UnderDevelopmentComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ UnderDevelopmentComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(UnderDevelopmentComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/under-development/under-development.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'soer-under-development', 5 | templateUrl: './under-development.component.html', 6 | styleUrls: ['./under-development.component.scss'] 7 | }) 8 | export class UnderDevelopmentComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/video-player/video-player.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 | 7 |
8 |
9 | 10 | 11 |
12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/dumb/video-player/video-player.component.scss: -------------------------------------------------------------------------------- 1 | .player-container { 2 | background: #fff; 3 | margin: 0 auto; 4 | width: auto; 5 | position: absolute; 6 | top: 50%; 7 | right: 20px; 8 | left: 20px; 9 | z-index: 1; 10 | cursor: default; 11 | transform: translateY(-50%); 12 | 13 | &-width { 14 | max-width: 960px; 15 | } 16 | 17 | .player-wrapper { 18 | display: block; 19 | box-shadow: 0 1px 2px -2px rgb(0 0 0 / 16%), 0 3px 6px 0 rgb(0 0 0 / 12%), 0 5px 12px 4px rgb(0 0 0 / 9%); 20 | } 21 | 22 | @media screen and (min-width: 768px) { 23 | .player-wrapper { 24 | height: 540px; 25 | } 26 | } 27 | 28 | @media screen and (max-width: 768px) { 29 | .player-wrapper { 30 | height: 320px; 31 | 32 | } 33 | } 34 | } 35 | 36 | ::ng-deep iframe { 37 | width: 100%; 38 | height: 100%; 39 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/login/auth/auth.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/login/auth/auth.component.scss: -------------------------------------------------------------------------------- 1 | nz-spin { 2 | position: fixed; 3 | top: 50%; 4 | left: 50%; 5 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/login/auth/auth.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AuthComponent } from './auth.component'; 4 | 5 | describe('AuthComponent', () => { 6 | let component: AuthComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [AuthComponent], 12 | }).compileComponents(); 13 | 14 | fixture = TestBed.createComponent(AuthComponent); 15 | component = fixture.componentInstance; 16 | fixture.detectChanges(); 17 | }); 18 | 19 | it('should create', () => { 20 | expect(component).toBeTruthy(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/login/auth/auth.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute, Router } from '@angular/router'; 3 | import { AuthService } from '@soer/sr-auth'; 4 | 5 | @Component({ 6 | selector: 'soer-auth', 7 | templateUrl: './auth.component.html', 8 | styleUrls: ['./auth.component.scss'], 9 | }) 10 | export class AuthComponent implements OnInit { 11 | private jwt: string | null = null; 12 | constructor( 13 | private route: ActivatedRoute, 14 | private router: Router 15 | ) {} 16 | 17 | ngOnInit(): void { 18 | this.jwt = this.route.snapshot.queryParams?.['jwt'] ?? null; 19 | this.checkJWT(this.jwt); 20 | } 21 | 22 | checkJWT(token: string | null): void { 23 | if (token) { 24 | this.jwt = token; 25 | localStorage.setItem('token', this.jwt); 26 | this.redirectToHome(); 27 | return; 28 | } 29 | this.redirectToLogin(); 30 | } 31 | 32 | redirectToHome(): void { 33 | this.router.navigate(['pages']); 34 | } 35 | 36 | redirectToLogin(): void { 37 | this.router.navigate(['login']); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/login/login-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import { AuthComponent } from './auth/auth.component'; 4 | import { LoginComponent } from './login.component'; 5 | 6 | const routes: Routes = [ 7 | { path: '', component: LoginComponent }, 8 | { path: 'auth', component: AuthComponent }, 9 | ]; 10 | 11 | @NgModule({ 12 | imports: [RouterModule.forChild(routes)], 13 | exports: [RouterModule] 14 | }) 15 | export class LoginRoutesModule { } 16 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/login/login.component.css: -------------------------------------------------------------------------------- 1 | 2 | .login-form { 3 | max-width: 300px; 4 | min-width: 300px; 5 | min-height: 300px; 6 | position: absolute; 7 | left: 50%; 8 | top: 50%; 9 | margin: -150px 0 0 -150px; 10 | } 11 | .login-form_title { 12 | text-align: center; 13 | } 14 | 15 | .login-form-margin { 16 | margin-bottom: 16px; 17 | } 18 | 19 | .login-form-forgot { 20 | float: right; 21 | } 22 | 23 | .login-form-button { 24 | width: 100%; 25 | } 26 | nz-spin { 27 | position: fixed; 28 | top: 50%; 29 | left: 50%; 30 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/login/login.component.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { AuthService } from '@soer/sr-auth'; 4 | import { environment } from '../../../environments/environment'; 5 | 6 | @Component({ 7 | selector: 'soer-login', 8 | templateUrl: './login.component.html', 9 | styleUrls: ['./login.component.css'] 10 | }) 11 | export class LoginComponent implements OnInit { 12 | 13 | public loading = true; 14 | 15 | constructor( 16 | private auth: AuthService, 17 | private router: Router) { } 18 | 19 | ngOnInit(): void { 20 | if (this.auth.token) { 21 | this.router.navigate(['pages']); 22 | return; 23 | } 24 | this.loading = false; 25 | } 26 | 27 | oAuthLogin(provider: 'patreon' | 'google' | 'yandex'): void { 28 | 29 | const urls = { 30 | 'patreon': environment.patreonAuthUrl, 31 | 'google': environment.googleAuthUrl, 32 | 'yandex': environment.yandexAuthUrl 33 | }; 34 | 35 | document.location = urls[provider]; 36 | return; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/login/login.module.ts: -------------------------------------------------------------------------------- 1 | import { NzFormModule } from 'ng-zorro-antd/form'; 2 | import { NzButtonModule } from 'ng-zorro-antd/button'; 3 | import { NzInputModule } from 'ng-zorro-antd/input'; 4 | import { NzInputNumberModule } from 'ng-zorro-antd/input-number'; 5 | import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; 6 | import { NgModule } from '@angular/core'; 7 | import { LoginComponent } from './login.component'; 8 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 9 | import { CommonModule } from '@angular/common'; 10 | import { LoginRoutesModule } from './login-routing.module'; 11 | import { HttpClient } from '@angular/common/http'; 12 | import { NzSpinModule } from 'ng-zorro-antd/spin'; 13 | import { AuthComponent } from './auth/auth.component'; 14 | 15 | 16 | @NgModule({ 17 | imports: [ 18 | CommonModule, 19 | FormsModule, 20 | LoginRoutesModule, 21 | ReactiveFormsModule, 22 | NzFormModule, 23 | NzButtonModule, 24 | NzInputModule, 25 | NzInputNumberModule, 26 | NzCheckboxModule, 27 | NzSpinModule 28 | ], 29 | providers: [HttpClient], 30 | declarations: [LoginComponent, AuthComponent], 31 | exports: [LoginComponent] 32 | }) 33 | export class LoginModule { } 34 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/abstracte/abstracte.const.ts: -------------------------------------------------------------------------------- 1 | import { BusKey } from "@soer/mixed-bus"; 2 | 3 | export const WORKBOOK_TAG = 'workbook'; 4 | export const WORKBOOKS_TAG = 'workbooks'; 5 | 6 | const sid = Symbol(WORKBOOKS_TAG); 7 | 8 | export interface WorkbookKey extends BusKey { 9 | wid: string; 10 | } 11 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/abstracte/edit-abstracte-form/edit-abstracte-form.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | {{block.text}} 10 |
11 |
12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/abstracte/edit-abstracte-form/edit-abstracte-form.component.scss: -------------------------------------------------------------------------------- 1 | .ant-btn { 2 | &-save, 3 | &-return { 4 | vertical-align: -4px; 5 | float: right; 6 | } 7 | 8 | &-return { 9 | margin-right: 12px; 10 | } 11 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/abstracte/edit-abstracte-form/edit-abstracte-form.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { EditAbstracteFormComponent } from './edit-abstracte-form.component'; 4 | 5 | describe('EditAbstracteFormComponent', () => { 6 | let component: EditAbstracteFormComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [EditAbstracteFormComponent], 12 | }).compileComponents(); 13 | 14 | fixture = TestBed.createComponent(EditAbstracteFormComponent); 15 | component = fixture.componentInstance; 16 | fixture.detectChanges(); 17 | }); 18 | 19 | it('should create', () => { 20 | expect(component).toBeTruthy(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/abstracte/edit-abstracte-page/edit-abstracte-page.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Loading... 9 | 10 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/abstracte/edit-abstracte-page/edit-abstracte-page.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/app/pages/modules/abstracte/edit-abstracte-page/edit-abstracte-page.component.scss -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/abstracte/list-abstracte-page/list-abstracte-page.component.scss: -------------------------------------------------------------------------------- 1 | .personal-target { 2 | ::ng-deep .ant-card-body { 3 | min-height: 10em; 4 | max-height: 10em; 5 | overflow: hidden; 6 | } 7 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/abstracte/list-abstracte-page/list-abstracte-page.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { ANY_SERVICE, MixedBusModule } from '@soer/mixed-bus'; 3 | import { SrDTOModule } from '@soer/sr-dto'; 4 | import { ApplicationService } from '../../../../services/application.service'; 5 | 6 | import { ListAbstractePageComponent } from './list-abstracte-page.component'; 7 | 8 | describe('ListAbstractePageComponent', () => { 9 | let component: ListAbstractePageComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async () => { 13 | await TestBed.configureTestingModule({ 14 | declarations: [ ListAbstractePageComponent ], 15 | imports: [ 16 | MixedBusModule, 17 | SrDTOModule 18 | ], 19 | providers: [ 20 | {provide: ApplicationService, useValue: {}}, 21 | {provide: 'workbooks', useValue: ANY_SERVICE}, 22 | {provide: 'workbook', useValue: ANY_SERVICE}, 23 | ] 24 | }) 25 | .compileComponents(); 26 | }); 27 | 28 | beforeEach(() => { 29 | fixture = TestBed.createComponent(ListAbstractePageComponent); 30 | component = fixture.componentInstance; 31 | fixture.detectChanges(); 32 | }); 33 | 34 | it('should create', () => { 35 | expect(component).toBeTruthy(); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/abstracte/view-abstracte-page/view-abstracte-page.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{workbook.text}} 4 | 5 | 6 | {{block.text}} 7 | 8 | 9 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/abstracte/view-abstracte-page/view-abstracte-page.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/app/pages/modules/abstracte/view-abstracte-page/view-abstracte-page.component.scss -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/abstracte/view-abstracte-page/view-abstracte-page.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | import { BusEmitter } from '@soer/mixed-bus'; 4 | import { DataStoreService, DtoPack } from '@soer/sr-dto'; 5 | import { WorkbookModel } from '@soer/sr-editor'; 6 | import { Observable } from 'node_modules/rxjs/dist/types'; 7 | import { parseJsonDTOPack } from '../../../../api/json.dto.helpers'; 8 | 9 | @Component({ 10 | selector: 'soer-view-abstracte-page', 11 | templateUrl: './view-abstracte-page.component.html', 12 | styleUrls: ['./view-abstracte-page.component.scss'] 13 | }) 14 | export class ViewAbstractePageComponent { 15 | 16 | public workbook$: Observable>; 17 | private workbookId: BusEmitter; 18 | 19 | constructor( 20 | private store$: DataStoreService, 21 | private route: ActivatedRoute 22 | ) { 23 | this.workbookId = this.route.snapshot.data['workbook']; 24 | this.workbook$ = parseJsonDTOPack(this.store$.of(this.workbookId), 'workbook'); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/certificate/certificate.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { CertificateComponent } from './certificate/certificate.component'; 4 | import { NzButtonModule } from 'ng-zorro-antd/button'; 5 | import { RouterModule } from '@angular/router'; 6 | import { NzAlertModule } from 'ng-zorro-antd/alert'; 7 | import { NzDividerModule } from 'ng-zorro-antd/divider'; 8 | import { NzIconModule } from 'ng-zorro-antd/icon'; 9 | import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; 10 | import { FormsModule } from '@angular/forms'; 11 | import { NzInputModule } from 'ng-zorro-antd/input'; 12 | import { SrDTOModule } from '@soer/sr-dto'; 13 | 14 | 15 | 16 | @NgModule({ 17 | declarations: [ 18 | CertificateComponent 19 | ], 20 | imports: [ 21 | CommonModule, 22 | CommonModule, 23 | NzButtonModule, 24 | NzAlertModule, 25 | NzDividerModule, 26 | NzIconModule, 27 | NzCheckboxModule, 28 | NzInputModule, 29 | RouterModule, 30 | FormsModule, 31 | SrDTOModule 32 | ] 33 | }) 34 | export class CertificateModule { } 35 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/certificate/certificate/certificate.component.scss: -------------------------------------------------------------------------------- 1 | ul.features-list { 2 | color: #6B7A90; 3 | font-size: 1.2em; 4 | min-height: 13rem; 5 | margin: 0; 6 | padding: 0; 7 | } 8 | .features-list li { 9 | margin-top: 0.2rem; 10 | list-style: none; 11 | padding: 0; 12 | text-align: left; 13 | } 14 | 15 | .certificate { 16 | padding: 2rem; 17 | 18 | .information { 19 | margin: 1rem; 20 | } 21 | 22 | .valid-date { 23 | text-align: right; 24 | color: #1890ff; 25 | } 26 | } 27 | 28 | 29 | @media screen and (min-width: 1024px) { 30 | .certificate.done { 31 | width: 40%; 32 | } 33 | } 34 | 35 | @media screen and (max-width: 1024px) { 36 | .certificate.done { 37 | width: 90%; 38 | } 39 | } 40 | 41 | 42 | .certificate.done { 43 | margin: auto; 44 | border: 1px solid lightgray; 45 | border-radius: 5px; 46 | h2 { 47 | text-align: center; 48 | text-transform: uppercase; 49 | } 50 | 51 | .controls { 52 | text-align: center; 53 | } 54 | } 55 | 56 | .certificate.start { 57 | width: 100%; 58 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/compose-video-player/compose-video-player.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/compose-video-player/compose-video-player.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/app/pages/modules/compose-video-player/compose-video-player.component.scss -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/compose-video-player/compose-video-player.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpClientTestingModule } from '@angular/common/http/testing'; 2 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { RouterTestingModule } from '@angular/router/testing'; 4 | 5 | import { ComposeVideoPlayerComponent } from './compose-video-player.component'; 6 | 7 | describe('ComposeVideoPlayerComponent', () => { 8 | let component: ComposeVideoPlayerComponent; 9 | let fixture: ComponentFixture; 10 | 11 | beforeEach(async () => { 12 | await TestBed.configureTestingModule({ 13 | declarations: [ ComposeVideoPlayerComponent ], 14 | imports: [ 15 | HttpClientTestingModule, 16 | RouterTestingModule, 17 | ], 18 | }) 19 | .compileComponents(); 20 | }); 21 | 22 | beforeEach(() => { 23 | fixture = TestBed.createComponent(ComposeVideoPlayerComponent); 24 | component = fixture.componentInstance; 25 | fixture.detectChanges(); 26 | }); 27 | 28 | it('should create', () => { 29 | expect(component).toBeTruthy(); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/compose-video-player/compose-video-player.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnDestroy, OnInit } from '@angular/core'; 2 | import { ActivatedRoute, Router } from '@angular/router'; 3 | import { ANY_SERVICE, MixedBusService } from '@soer/mixed-bus'; 4 | import { Subscription } from 'rxjs'; 5 | import { WatchVideoEvent } from '../../../api/progress/events/watch-video.event'; 6 | 7 | @Component({ 8 | selector: 'soer-compose-video-player', 9 | templateUrl: './compose-video-player.component.html', 10 | styleUrls: ['./compose-video-player.component.scss'] 11 | }) 12 | export class ComposeVideoPlayerComponent implements OnInit, OnDestroy { 13 | 14 | public videoId = null; 15 | public videoSource: 'youtube' | 'vimeo' = 'youtube'; 16 | subscription: Subscription | null = null; 17 | constructor(private route: ActivatedRoute, private router: Router, private Bus$: MixedBusService) { } 18 | 19 | ngOnInit(): void { 20 | this.subscription = this.route.params.subscribe( 21 | (params) => { 22 | this.videoId = params?.['videoId']; 23 | this.videoSource = params?.['videoSource'] || 'youtube'; 24 | this.Bus$.publish(new WatchVideoEvent(ANY_SERVICE, {videoId: this.videoId + ''})); 25 | } 26 | ); 27 | } 28 | 29 | ngOnDestroy(): void { 30 | if (this.subscription) { 31 | this.subscription.unsubscribe(); 32 | } 33 | } 34 | 35 | onClose(): void { 36 | this.router.navigate(['.'], {relativeTo: this.route.parent, queryParams: {fid: this.route.snapshot.queryParams['fid']}}); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/overview/info/info.component.scss: -------------------------------------------------------------------------------- 1 | ::ng-deep .ant-card-bordered { 2 | border-radius: 5px; 3 | } 4 | 5 | .contacts-level { 6 | ::ng-deep i.anticon { 7 | color: #1890ff; 8 | font-size: 3rem; 9 | } 10 | 11 | .contact { 12 | display: flex; 13 | flex-direction: row; 14 | &_icon { 15 | padding: 0 2em 0 0; 16 | } 17 | &_text { 18 | min-height: 6rem; 19 | p { 20 | font-size: 1.5em; 21 | color: rgba(0,0,0,.45);; 22 | } 23 | } 24 | } 25 | } 26 | 27 | .social-level { 28 | 29 | 30 | .social { 31 | display: flex; 32 | flex-direction: row; 33 | &_icon { 34 | padding: 0 2em 0 0; 35 | ::ng-deep i.anticon { 36 | color: #1890ff; 37 | font-size: 3rem; 38 | } 39 | } 40 | &_text { 41 | min-height: 7rem; 42 | p { 43 | font-size: 1.1rem; 44 | color: rgba(0,0,0,.45);; 45 | } 46 | } 47 | } 48 | } 49 | 50 | 51 | .link { 52 | text-align: right; 53 | ::ng-deep i.anticon { 54 | color: #1890ff; 55 | font-size: 1.5rem; 56 | } 57 | } 58 | 59 | .general-target { 60 | color: #535FD7; 61 | background-color: #E9EDF3; 62 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/overview/info/info.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { InfoComponent } from './info.component'; 4 | 5 | describe('InfoComponent', () => { 6 | let component: InfoComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [InfoComponent], 12 | }).compileComponents(); 13 | 14 | fixture = TestBed.createComponent(InfoComponent); 15 | component = fixture.componentInstance; 16 | fixture.detectChanges(); 17 | }); 18 | 19 | it('should create', () => { 20 | expect(component).toBeTruthy(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/overview/info/info.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | 4 | @Component({ 5 | selector: 'soer-info', 6 | templateUrl: './info.component.html', 7 | styleUrls: ['./info.component.scss'], 8 | }) 9 | export class InfoComponent { 10 | data; 11 | constructor(private route: ActivatedRoute, 12 | ) { 13 | this.data = this.route.snapshot.data;} 14 | } 15 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/overview/metrics/metrics.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { MetricsComponent } from './metrics.component'; 4 | 5 | describe('MetricsComponent', () => { 6 | let component: MetricsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [MetricsComponent], 12 | }).compileComponents(); 13 | 14 | fixture = TestBed.createComponent(MetricsComponent); 15 | component = fixture.componentInstance; 16 | fixture.detectChanges(); 17 | }); 18 | 19 | it('should create', () => { 20 | expect(component).toBeTruthy(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/payment/pay.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { PayService } from './pay.service'; 4 | 5 | describe('PayService', () => { 6 | let service: PayService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(PayService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/payment/pay.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | 4 | 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class PayService { 10 | 11 | 12 | } 13 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/payment/payment.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { PayFormComponent } from './pay-form/pay-form.component'; 4 | import { PayService } from './pay.service'; 5 | import { NzButtonModule } from 'ng-zorro-antd/button'; 6 | import { RouterModule } from '@angular/router'; 7 | import { NzAlertModule } from 'ng-zorro-antd/alert'; 8 | import { NzDividerModule } from 'ng-zorro-antd/divider'; 9 | import { NzIconModule } from 'ng-zorro-antd/icon'; 10 | import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; 11 | import { FormsModule } from '@angular/forms'; 12 | import { NzInputModule } from 'ng-zorro-antd/input'; 13 | import { NzSpinModule } from 'ng-zorro-antd/spin'; 14 | import { SrDTOModule } from '@soer/sr-dto'; 15 | import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm'; 16 | import { NzStatisticModule } from 'ng-zorro-antd/statistic'; 17 | 18 | 19 | 20 | @NgModule({ 21 | declarations: [ 22 | PayFormComponent 23 | ], 24 | providers: [ 25 | PayService 26 | ], 27 | imports: [ 28 | CommonModule, 29 | NzButtonModule, 30 | NzAlertModule, 31 | NzDividerModule, 32 | NzIconModule, 33 | NzCheckboxModule, 34 | NzInputModule, 35 | NzPopconfirmModule, 36 | NzStatisticModule, 37 | NzSpinModule, 38 | RouterModule, 39 | FormsModule, 40 | SrDTOModule 41 | ] 42 | }) 43 | export class PaymentModule { } 44 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/questions/file-extension.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'fileExtension' 5 | }) 6 | export class FileExtensionPipe implements PipeTransform { 7 | 8 | transform(value: string, ...args: unknown[]): unknown { 9 | return value.split('.').pop(); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/questions/list-questions-page/list-questions-page.component.scss: -------------------------------------------------------------------------------- 1 | .qa-list-item { 2 | min-height: 5rem; 3 | align-items: baseline; 4 | } 5 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/questions/list-questions-page/list-questions-page.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpClientTestingModule } from '@angular/common/http/testing'; 2 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { ActivatedRoute } from '@angular/router'; 4 | import { RouterTestingModule } from '@angular/router/testing'; 5 | import { ANY_SERVICE } from '@soer/mixed-bus'; 6 | import { OnlyWithAnaswerPipe } from '../only-with-anaswer.pipe'; 7 | 8 | import { ListQuestionsPageComponent } from './list-questions-page.component'; 9 | 10 | describe('ListQuestionsPageComponent', () => { 11 | let component: ListQuestionsPageComponent; 12 | let fixture: ComponentFixture; 13 | 14 | beforeEach(async () => { 15 | await TestBed.configureTestingModule({ 16 | declarations: [ ListQuestionsPageComponent, OnlyWithAnaswerPipe ], 17 | imports: [ 18 | HttpClientTestingModule, 19 | RouterTestingModule, 20 | ], 21 | providers: [ 22 | {provide: ActivatedRoute, useValue: {snapshot: {data: {questions: ANY_SERVICE}}}}, 23 | {provide: 'question', useValue: ANY_SERVICE}, 24 | {provide: 'questionsAll', useValue: ANY_SERVICE} 25 | ] 26 | }) 27 | .compileComponents(); 28 | }); 29 | 30 | beforeEach(() => { 31 | fixture = TestBed.createComponent(ListQuestionsPageComponent); 32 | component = fixture.componentInstance; 33 | fixture.detectChanges(); 34 | }); 35 | 36 | it('should create', () => { 37 | expect(component).toBeTruthy(); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/questions/only-with-anaswer.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import { QuestionModel } from '../../../api/questions/question.model'; 3 | 4 | @Pipe({ 5 | name: 'onlyWithAnaswer' 6 | }) 7 | export class OnlyWithAnaswerPipe implements PipeTransform { 8 | 9 | transform(value: QuestionModel[] | null, ...args: unknown[]): unknown { 10 | if (Array.isArray(value)) { 11 | return value.filter(question => question.url !== null); 12 | } 13 | return []; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/questions/question-form/question-form.component.html: -------------------------------------------------------------------------------- 1 |

Задайте свой вопрос

2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
-------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/questions/question-form/question-form.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/app/pages/modules/questions/question-form/question-form.component.scss -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/questions/question-form/question-form.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import {FormBuilder, UntypedFormBuilder} from '@angular/forms'; 3 | import { ANY_SERVICE } from '@soer/mixed-bus'; 4 | 5 | import { QuestionFormComponent } from './question-form.component'; 6 | 7 | describe('QuestionFormComponent', () => { 8 | let component: QuestionFormComponent; 9 | let fixture: ComponentFixture; 10 | 11 | beforeEach(async () => { 12 | await TestBed.configureTestingModule({ 13 | declarations: [ QuestionFormComponent ], 14 | providers: [ 15 | FormBuilder, 16 | {provide: 'questions', useValue: ANY_SERVICE}, 17 | {provide: 'question', useValue: ANY_SERVICE}, 18 | UntypedFormBuilder 19 | ] 20 | }) 21 | .compileComponents(); 22 | }); 23 | 24 | beforeEach(() => { 25 | fixture = TestBed.createComponent(QuestionFormComponent); 26 | component = fixture.componentInstance; 27 | fixture.detectChanges(); 28 | }); 29 | 30 | it('should create', () => { 31 | expect(component).toBeTruthy(); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/questions/question-rules/question-rules.component.html: -------------------------------------------------------------------------------- 1 |

Правила

2 |

Данный раздел прездназначен для обмена опытом, вы можете задать любой вопрос, 3 | касающийся программирования и профессиональной деятельности. 4 |

5 |

Важно! Ответ на вопрос не является персональным, он может быть опубликован 6 | публично на ютуб канале или подкасте, а так же может быть доступен другим участникам сообщества.

7 | 8 | Публикуя свой вопрос, вы соглашаетесь и гарантируете следующее: 9 |
    10 |
  • Вопрос не содержит информации, нарушающей законодательство РФ
  • 11 |
  • Вопрос касается профессиональной деятельности и не содержит личной информации, 12 | охраняемой федеральным законодательством
  • 13 |
  • Вопрос и ответ на него могут быть опубликованы публично в сети Интернет, дополнительного согласия на это не требуется
  • 14 |
-------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/questions/question-rules/question-rules.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/app/pages/modules/questions/question-rules/question-rules.component.scss -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/questions/question-rules/question-rules.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { QuestionRulesComponent } from './question-rules.component'; 4 | 5 | describe('QuestionRulesComponent', () => { 6 | let component: QuestionRulesComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ QuestionRulesComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(QuestionRulesComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/questions/question-rules/question-rules.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'soer-question-rules', 5 | templateUrl: './question-rules.component.html', 6 | styleUrls: ['./question-rules.component.scss'] 7 | }) 8 | export class QuestionRulesComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/questions/question-view/question-view.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 |
6 |
7 |

{{question.question}}

8 |
9 |
10 |
11 | 12 |

Нет ответа

13 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/questions/question-view/question-view.component.scss: -------------------------------------------------------------------------------- 1 | .question_answer { 2 | padding: 2em; 3 | height: 100%; 4 | overflow: auto; 5 | width: 100%; 6 | 7 | .audio-player { 8 | width: 100%; 9 | display: inline-block; 10 | text-align: center; 11 | } 12 | .text { 13 | overflow: auto; 14 | margin: 2em; 15 | } 16 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/questions/question-view/question-view.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpClientTestingModule } from '@angular/common/http/testing'; 2 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { ActivatedRoute } from '@angular/router'; 4 | import { RouterTestingModule } from '@angular/router/testing'; 5 | import { ANY_SERVICE } from '@soer/mixed-bus'; 6 | 7 | import { QuestionViewComponent } from './question-view.component'; 8 | 9 | describe('QuestionViewComponent', () => { 10 | let component: QuestionViewComponent; 11 | let fixture: ComponentFixture; 12 | 13 | beforeEach(async () => { 14 | await TestBed.configureTestingModule({ 15 | declarations: [ QuestionViewComponent ], 16 | imports: [ 17 | HttpClientTestingModule, 18 | RouterTestingModule, 19 | ], 20 | providers: [ 21 | {provide: ActivatedRoute, useValue: {snapshot: {data: {question: ANY_SERVICE}}} }, 22 | {provide: 'question', useValue: ANY_SERVICE}, 23 | {provide: 'questionsAll', useValue: ANY_SERVICE} 24 | ] 25 | }) 26 | .compileComponents(); 27 | }); 28 | 29 | beforeEach(() => { 30 | fixture = TestBed.createComponent(QuestionViewComponent); 31 | component = fixture.componentInstance; 32 | fixture.detectChanges(); 33 | }); 34 | 35 | it('should create', () => { 36 | expect(component).toBeTruthy(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/questions/question-view/question-view.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Inject, OnInit } from '@angular/core'; 2 | import { map, Observable } from 'rxjs'; 3 | import { ActivatedRoute } from '@angular/router'; 4 | import { QuestionModel } from '../../../../api/questions/question.model'; 5 | import { BusMessage, BusEmitter, MixedBusService } from '@soer/mixed-bus'; 6 | import { environment } from '../../../../../environments/environment'; 7 | import { DataStoreService } from '@soer/sr-dto'; 8 | 9 | @Component({ 10 | selector: 'soer-question-view', 11 | templateUrl: './question-view.component.html', 12 | styleUrls: ['./question-view.component.scss'] 13 | }) 14 | export class QuestionViewComponent { 15 | public readonly hostUrl = environment.host; 16 | public question$: Observable; 17 | private questionId: BusEmitter; 18 | constructor( private store$: DataStoreService, 19 | private route: ActivatedRoute) { 20 | this.questionId = this.route.snapshot.data['question']; 21 | this.question$ = this.store$.of(this.questionId).pipe(map( 22 | (data: BusMessage | null) => { 23 | return data?.payload?.items ?? []; 24 | } 25 | )); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/questions/questions.const.ts: -------------------------------------------------------------------------------- 1 | import { BusKey } from "@soer/mixed-bus"; 2 | 3 | export const QUESTION_TAG = 'question'; 4 | export const QUESTIONS_TAG = 'questions'; 5 | 6 | const sid = Symbol(QUESTIONS_TAG); 7 | 8 | 9 | export interface QuestionKey extends BusKey { 10 | qid: string; 11 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/questions/yt-from-url.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'ytFromUrl' 5 | }) 6 | export class YtFromUrlPipe implements PipeTransform { 7 | 8 | transform(value: string, ...args: unknown[]): unknown { 9 | return value.split('.').splice(-2, 1).pop(); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/roadmap/roadmap.component.scss: -------------------------------------------------------------------------------- 1 | 2 | .warning-message { 3 | height: 100%; 4 | margin: auto; 5 | } 6 | 7 | @media screen and (min-width: 768px) { 8 | .warning-message { 9 | width: 70%; 10 | } 11 | } 12 | 13 | @media screen and (max-width: 768px) { 14 | .warning-message { 15 | width: 100%; 16 | } 17 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/roadmap/roadmap.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpClientTestingModule } from '@angular/common/http/testing'; 2 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { RouterTestingModule } from '@angular/router/testing'; 4 | 5 | import { RoadmapComponent } from './roadmap.component'; 6 | 7 | describe('RoadmapComponent', () => { 8 | let component: RoadmapComponent; 9 | let fixture: ComponentFixture; 10 | 11 | beforeEach(async () => { 12 | await TestBed.configureTestingModule({ 13 | declarations: [ RoadmapComponent ], 14 | imports: [ 15 | HttpClientTestingModule, 16 | RouterTestingModule, 17 | ], 18 | }) 19 | .compileComponents(); 20 | }); 21 | 22 | beforeEach(() => { 23 | fixture = TestBed.createComponent(RoadmapComponent); 24 | component = fixture.componentInstance; 25 | fixture.detectChanges(); 26 | }); 27 | 28 | it('should create', () => { 29 | expect(component).toBeTruthy(); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/roadmap/roadmap.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | import { PersonalTarget, RoadmapTask } from '../../../api/targets/target.interface'; 4 | import { environment } from '../../../../environments/environment'; 5 | 6 | @Component({ 7 | selector: 'soer-roadmap', 8 | templateUrl: './roadmap.component.html', 9 | styleUrls: ['./roadmap.component.scss'] 10 | }) 11 | export class RoadmapComponent implements OnInit { 12 | 13 | target: PersonalTarget = { 14 | title: '', 15 | overview: '', 16 | activity: '', 17 | tasks: [] 18 | }; 19 | total = 0; 20 | 21 | constructor(private route: ActivatedRoute) { } 22 | 23 | ngOnInit(): void { 24 | this.target = this.route.snapshot.data['target'] || this.target; 25 | this.target.tasks.forEach(task => task.progress = this.calcProgress(task.children)); 26 | this.total = this.calcProgress(this.target.tasks); 27 | } 28 | 29 | url(file: any): string { 30 | return environment.privateAssetsUrl + file; 31 | } 32 | 33 | private calcProgress(tasks: RoadmapTask[]) { 34 | if ((tasks ?? []).length > 0) { 35 | const value = tasks.reduce( (r, v) => ({total: r.total + 100, real: r.real + v.progress}), {total: 0, real: 0}); 36 | return Math.floor(value.real / value.total * 100); 37 | } 38 | return 0; 39 | } 40 | 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/streams/streams.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpClientTestingModule } from '@angular/common/http/testing'; 2 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { RouterTestingModule } from '@angular/router/testing'; 4 | 5 | import { StreamsComponent } from './streams.component'; 6 | 7 | describe('StreamsComponent', () => { 8 | let component: StreamsComponent; 9 | let fixture: ComponentFixture; 10 | 11 | beforeEach(async () => { 12 | await TestBed.configureTestingModule({ 13 | declarations: [ StreamsComponent ], 14 | imports: [ 15 | HttpClientTestingModule, 16 | RouterTestingModule, 17 | ], 18 | }).compileComponents(); 19 | }); 20 | 21 | beforeEach(() => { 22 | fixture = TestBed.createComponent(StreamsComponent); 23 | component = fixture.componentInstance; 24 | fixture.detectChanges(); 25 | }); 26 | 27 | it('should create', () => { 28 | expect(component).toBeTruthy(); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/calc-progress.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { CalcProgressPipe } from './calc-progress.pipe'; 2 | 3 | describe('CalcProgressPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new CalcProgressPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/calc-progress.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import { TargetModel } from '../../../api/targets/target.interface'; 3 | 4 | @Pipe({ 5 | name: 'calcProgress' 6 | }) 7 | export class CalcProgressPipe implements PipeTransform { 8 | 9 | transform(value: TargetModel, ...args: unknown[]): unknown { 10 | return value.tasks?.length > 0 ? this.calcProgress(value) : value.progress; 11 | } 12 | 13 | private calcProgress(target: TargetModel): number { 14 | const value = target.tasks.reduce((r, v) => ({ total: r.total + 100, real: r.real + v.progress }), { total: 0, real: 0 }); 15 | return value.total > 0 ? Math.floor(value.real / value.total * 100) : 0; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/count-closed-tasks.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import { TargetModel } from '../../../api/targets/target.interface'; 3 | import { DONE_PROGRESS } from './targets.const'; 4 | 5 | @Pipe({ 6 | name: 'countClosedTasks' 7 | }) 8 | export class CountClosedTasksPipe implements PipeTransform { 9 | 10 | transform(target: TargetModel, ...args: unknown[]): unknown { 11 | return target.tasks?.length > 0 12 | ? 13 | target.tasks.filter(task => task.progress === DONE_PROGRESS).length 14 | : 15 | 0 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/count-open-tasks.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import { TargetModel } from '../../../api/targets/target.interface'; 3 | import { DONE_PROGRESS } from './targets.const'; 4 | 5 | @Pipe({ 6 | name: 'countOpenTasks' 7 | }) 8 | export class CountOpenTasksPipe implements PipeTransform { 9 | 10 | transform(target: TargetModel, ...args: unknown[]): unknown { 11 | return target.tasks?.length > 0 12 | ? 13 | target.tasks.filter(task => task.progress < DONE_PROGRESS).length 14 | : 15 | 0 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/list-aims-page/list-aims-page.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | import { ANY_SERVICE, MixedBusModule } from '@soer/mixed-bus'; 4 | import { SrDTOModule } from '@soer/sr-dto'; 5 | import { NzNotificationService } from 'ng-zorro-antd/notification'; 6 | 7 | import { ListAimsPageComponent } from './list-aims-page.component'; 8 | class MockNzNotificationService { 9 | 10 | } 11 | 12 | describe('ListAimsPageComponent', () => { 13 | let component: ListAimsPageComponent; 14 | let fixture: ComponentFixture; 15 | 16 | beforeEach(async () => { 17 | await TestBed.configureTestingModule({ 18 | declarations: [ ListAimsPageComponent ], 19 | imports: [ 20 | MixedBusModule, 21 | SrDTOModule 22 | ], 23 | providers: [ 24 | 25 | {provide: ActivatedRoute, useValue: {snapshot: {params: {}, data: {targets: ANY_SERVICE}}}}, 26 | {provide: 'target', useValue: ANY_SERVICE}, 27 | {provide: 'targets', useValue: ANY_SERVICE}, 28 | {provide: NzNotificationService, useClass: MockNzNotificationService} 29 | ] 30 | }) 31 | .compileComponents(); 32 | }); 33 | 34 | beforeEach(() => { 35 | fixture = TestBed.createComponent(ListAimsPageComponent); 36 | component = fixture.componentInstance; 37 | fixture.detectChanges(); 38 | }); 39 | 40 | it('should create', () => { 41 | expect(component).toBeTruthy(); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/list-targets-page/list-targets-page.component.scss: -------------------------------------------------------------------------------- 1 | .target-panel { 2 | padding: 16px 0 0 0; 3 | } 4 | 5 | .ant-btn { 6 | &-create { 7 | margin-bottom: 12px; 8 | } 9 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/list-targets-page/list-targets-page.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { ANY_SERVICE } from '@soer/mixed-bus'; 3 | 4 | import { ListTargetsPageComponent } from './list-targets-page.component'; 5 | 6 | describe('ListTargetsPageComponent', () => { 7 | let component: ListTargetsPageComponent; 8 | let fixture: ComponentFixture; 9 | 10 | beforeEach(async () => { 11 | await TestBed.configureTestingModule({ 12 | declarations: [ ListTargetsPageComponent ], 13 | providers: [ 14 | {provide: 'target', useValue: ANY_SERVICE}, 15 | {provide: 'targets', useValue: ANY_SERVICE}, 16 | 17 | ] 18 | }) 19 | .compileComponents(); 20 | }); 21 | 22 | beforeEach(() => { 23 | fixture = TestBed.createComponent(ListTargetsPageComponent); 24 | component = fixture.componentInstance; 25 | fixture.detectChanges(); 26 | }); 27 | 28 | it('should create', () => { 29 | expect(component).toBeTruthy(); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/list-targets-page/list-targets-page.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Inject, OnInit } from '@angular/core'; 2 | import { Observable } from 'rxjs'; 3 | import { parseJsonDTOPack } from '../../../../api/json.dto.helpers'; 4 | import { CommandDelete } from '@soer/sr-dto'; 5 | import { DtoPack } from '@soer/sr-dto'; 6 | import { DataStoreService } from '@soer/sr-dto'; 7 | import { BusEmitter } from '@soer/mixed-bus'; 8 | import { MixedBusService } from '@soer/mixed-bus'; 9 | import { TargetModel } from '../../../../api/targets/target.interface'; 10 | 11 | @Component({ 12 | selector: 'soer-list-targets-page', 13 | templateUrl: './list-targets-page.component.html', 14 | styleUrls: ['./list-targets-page.component.scss'] 15 | }) 16 | export class ListTargetsPageComponent { 17 | public targets$: Observable>; 18 | constructor( 19 | @Inject('targets') private targetsId: BusEmitter, 20 | @Inject('target') private targetId: BusEmitter, 21 | private bus$: MixedBusService, 22 | private store$: DataStoreService, 23 | ) { 24 | this.targets$ = parseJsonDTOPack(this.store$.of(this.targetsId), 'Targets list'); 25 | } 26 | 27 | onDelete(target: TargetModel): void { 28 | this.bus$.publish( 29 | new CommandDelete(this.targetId, {}, {tid: target.id}) 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/list-templates-page/list-templates-page.component.scss: -------------------------------------------------------------------------------- 1 | 2 | .template-options { 3 | text-align: right; 4 | } 5 | 6 | 7 | .template-options, 8 | .template-panel { 9 | padding: 16px 0 0 0; 10 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/list-templates-page/list-templates-page.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | import { RouterTestingModule } from '@angular/router/testing'; 4 | import { ANY_SERVICE } from '@soer/mixed-bus'; 5 | import { of } from 'rxjs'; 6 | 7 | import { ListTemplatesPageComponent } from './list-templates-page.component'; 8 | 9 | describe('ListTemplatesPageComponent', () => { 10 | let component: ListTemplatesPageComponent; 11 | let fixture: ComponentFixture; 12 | 13 | beforeEach(async () => { 14 | await TestBed.configureTestingModule({ 15 | declarations: [ ListTemplatesPageComponent ], 16 | imports: [ 17 | RouterTestingModule, 18 | ], 19 | providers: [ 20 | {provide: ActivatedRoute, useValue: {snapshot: {data: {templates: ANY_SERVICE}} }}, 21 | {provide: 'target', useValue: ANY_SERVICE}, 22 | {provide: 'template', useValue: ANY_SERVICE}, 23 | {provide: 'publicTemplates', useValue: ANY_SERVICE}, 24 | ] 25 | }) 26 | .compileComponents(); 27 | }); 28 | 29 | beforeEach(() => { 30 | fixture = TestBed.createComponent(ListTemplatesPageComponent); 31 | component = fixture.componentInstance; 32 | fixture.detectChanges(); 33 | }); 34 | 35 | it('should create', () => { 36 | expect(component).toBeTruthy(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/progress.helper.ts: -------------------------------------------------------------------------------- 1 | import { TargetModel } from "../../../api/targets/target.interface"; 2 | 3 | export function propagateProgress(target: TargetModel, progress: number): void { 4 | if (target.tasks?.length > 0) { 5 | target.tasks.forEach(task => propagateProgress(task, progress)); 6 | } 7 | target.progress = progress; 8 | } 9 | export function updateProgress(target: TargetModel): void { 10 | if (target.tasks?.length > 0) { 11 | target.tasks.forEach( task => updateProgress(task)); 12 | target.progress = calcProgress(target); 13 | } 14 | } 15 | 16 | export function calcProgress(target: TargetModel): number { 17 | const value = target.tasks.reduce((r, v) => ({ total: r.total + 100, real: r.real + v.progress }), { total: 0, real: 0 }); 18 | return value.total > 0 ? Math.floor(value.real / value.total * 100) : 0; 19 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/target-edit-form/target-edit-form.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 | Цель: 6 | 7 | 8 | 9 | Обязательное поле 10 | Макс. 140 символов 11 | 12 | 13 | 14 | 15 | 16 | Мотивация: 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 |
-------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/target-edit-form/target-edit-form.component.scss: -------------------------------------------------------------------------------- 1 | ::ng-deep .ant-form-item-control-input, 2 | ::ng-deep .ant-form-item-control-input-content { 3 | height: 100%; 4 | } 5 | .target_form { 6 | padding: 2em 1em 0 1em; 7 | height: 100%; 8 | overflow: auto; 9 | width: 100%; 10 | 11 | form { 12 | height: 100%; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: stretch; 16 | 17 | .title, .footer { 18 | flex-grow: 0; 19 | } 20 | .footer { 21 | flex-direction: row-reverse; 22 | button { 23 | width: 7rem; 24 | } 25 | } 26 | .content { 27 | flex-grow: 4; 28 | } 29 | 30 | ::ng-deep textarea { 31 | height: 100%; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/target-edit-form/target-edit-form.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import {FormBuilder, UntypedFormBuilder} from '@angular/forms'; 3 | import { ActivatedRoute } from '@angular/router'; 4 | import { ANY_SERVICE } from '@soer/mixed-bus'; 5 | 6 | import { TargetEditFormComponent } from './target-edit-form.component'; 7 | 8 | describe('TargetEditFormComponent', () => { 9 | let component: TargetEditFormComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async () => { 13 | await TestBed.configureTestingModule({ 14 | declarations: [ TargetEditFormComponent ], 15 | providers: [ 16 | {provide: ActivatedRoute, useValue: {snapshot: {data: {afterCommandDoneRedirectTo: ''}}}}, 17 | {provide: 'target', useValue: ANY_SERVICE}, 18 | FormBuilder, 19 | UntypedFormBuilder 20 | ] 21 | }) 22 | .compileComponents(); 23 | }); 24 | 25 | beforeEach(() => { 26 | fixture = TestBed.createComponent(TargetEditFormComponent); 27 | component = fixture.componentInstance; 28 | fixture.detectChanges(); 29 | }); 30 | 31 | it('should create', () => { 32 | expect(component).toBeTruthy(); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/targets.const.ts: -------------------------------------------------------------------------------- 1 | import { BusKey } from "@soer/mixed-bus"; 2 | 3 | export const TARGET_TAG = 'target'; 4 | export const TARGETS_TAG = 'targets'; 5 | 6 | export const DONE_PROGRESS = 100; 7 | export const UNDONE_PROGRESS = 0; 8 | 9 | export interface TargetKey extends BusKey { 10 | tid: string; 11 | } 12 | 13 | export interface TemplateKey extends BusKey { 14 | tid: string; 15 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/targets.helpers.ts: -------------------------------------------------------------------------------- 1 | import { TargetModel, TemplateModel } from "../../../api/targets/target.interface"; 2 | 3 | 4 | 5 | export function target2template(target: TargetModel): TemplateModel { 6 | 7 | const template: TemplateModel = JSON.parse(JSON.stringify(target)); 8 | const progressClear = (tmpTask: TemplateModel) => { 9 | tmpTask.progress = 0; 10 | if (tmpTask.tasks) { 11 | tmpTask.tasks?.forEach(progressClear); 12 | } else { 13 | tmpTask.tasks = []; 14 | } 15 | } 16 | progressClear(template); 17 | return template; 18 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/task-edit-form/task-edit-form.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/task-edit-form/task-edit-form.component.scss: -------------------------------------------------------------------------------- 1 | .task_form { 2 | padding: 2em; 3 | height: 100%; 4 | overflow: auto; 5 | width: 100%; 6 | display: flex; 7 | flex-direction: column; 8 | flex-wrap: nowrap; 9 | align-items: stretch; 10 | } 11 | 12 | button { 13 | margin: 0 0.5rem 0.5rem 0; 14 | } 15 | 16 | .task-desc { 17 | max-width: 30rem; 18 | width: 100%; 19 | margin: 0 1rem 0.5rem 0; 20 | border-width: 1px; 21 | } 22 | 23 | header { 24 | flex-grow: 1; 25 | max-height: 5rem; 26 | height: 5rem; 27 | } 28 | 29 | content { 30 | flex-grow: 1; 31 | padding: 0.5rem; 32 | overflow: auto; 33 | } 34 | 35 | footer { 36 | height: 2.5rem; 37 | max-height: 2.5rem; 38 | flex-grow: 1; 39 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/task-edit-form/task-edit-form.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | import { RouterTestingModule } from '@angular/router/testing'; 4 | import { ANY_SERVICE } from '@soer/mixed-bus'; 5 | 6 | import { TaskEditFormComponent } from './task-edit-form.component'; 7 | 8 | describe('TaskEditFormComponent', () => { 9 | let component: TaskEditFormComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async () => { 13 | await TestBed.configureTestingModule({ 14 | declarations: [ TaskEditFormComponent ], 15 | imports: [ 16 | RouterTestingModule, 17 | ], 18 | providers: [ 19 | {provide: ActivatedRoute, useValue: {snapshot: {data: {target: ANY_SERVICE}} }}, 20 | {provide: 'target', useValue: ANY_SERVICE}, 21 | {provide: 'template', useValue: ANY_SERVICE}, 22 | ] 23 | }) 24 | .compileComponents(); 25 | }); 26 | 27 | beforeEach(() => { 28 | fixture = TestBed.createComponent(TaskEditFormComponent); 29 | component = fixture.componentInstance; 30 | fixture.detectChanges(); 31 | }); 32 | 33 | it('should create', () => { 34 | expect(component).toBeTruthy(); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/task-tree-edit-form/task-tree-edit-form.component.scss: -------------------------------------------------------------------------------- 1 | .task_form { 2 | padding: 1.5em; 3 | height: 100%; 4 | overflow: auto; 5 | width: 100%; 6 | display: flex; 7 | flex-direction: column; 8 | flex-wrap: nowrap; 9 | align-items: stretch; 10 | 11 | .task-item { 12 | display: inline-block; 13 | margin: 0 0.5rem; 14 | } 15 | } 16 | 17 | nz-breadcrumb { 18 | margin: 0 0 2rem; 19 | } 20 | ::ng-deep .ant-timeline-item-head-custom { 21 | background-color: transparent; 22 | } 23 | 24 | ::ng-deep .ant-breadcrumb-link, ::ng-deep .ant-breadcrumb-separator { 25 | white-space: nowrap; 26 | max-width: 15rem; 27 | overflow: hidden; 28 | display: inline-block; 29 | text-overflow: ellipsis; 30 | } 31 | 32 | .back { 33 | position: absolute; 34 | } 35 | .target-title { 36 | padding-left: 1.5rem; 37 | } 38 | 39 | 40 | .task-desc { 41 | max-width: 30rem; 42 | width: 100%; 43 | margin: 0 1rem 0.5rem 0; 44 | border-width: 1px; 45 | } 46 | 47 | button { 48 | margin: 0 0.5rem 0.5rem 0; 49 | } 50 | 51 | header { 52 | flex-grow: 1; 53 | max-height: 5rem; 54 | height: 5rem; 55 | } 56 | 57 | content { 58 | flex-grow: 1; 59 | overflow: auto; 60 | padding: 2rem 10px 0rem 10px; 61 | margin: 1rem 0; 62 | background: #fbfbfb; 63 | border: 1px solid #d9d9d9; 64 | border-radius: 6px; 65 | } 66 | 67 | footer { 68 | height: 2.5rem; 69 | max-height: 2.5rem; 70 | flex-grow: 1; 71 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/task-tree-edit-form/task-tree-edit-form.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TaskTreeEditFormComponent } from './task-tree-edit-form.component'; 4 | 5 | describe('TaskTreeEditFormComponent', () => { 6 | let component: TaskTreeEditFormComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ TaskTreeEditFormComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(TaskTreeEditFormComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/template-create/template-create.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 |
6 |
7 | 8 |
9 |
10 | Публичный шаблон (будет виден другим пользователям) 11 |
12 |
13 | 14 |
15 |
16 |
-------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/template-create/template-create.component.scss: -------------------------------------------------------------------------------- 1 | .template-form { 2 | padding: 1em; 3 | } 4 | 5 | .form-item { 6 | padding: 0.5em 0; 7 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/modules/targets/template-create/template-create.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | import { RouterTestingModule } from '@angular/router/testing'; 4 | import { ANY_SERVICE } from '@soer/mixed-bus'; 5 | 6 | import { TemplateCreateComponent } from './template-create.component'; 7 | 8 | describe('TemplateCreateComponent', () => { 9 | let component: TemplateCreateComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async () => { 13 | await TestBed.configureTestingModule({ 14 | declarations: [ TemplateCreateComponent ], 15 | imports: [ 16 | RouterTestingModule, 17 | ], 18 | providers: [ 19 | {provide: ActivatedRoute, useValue: {snapshot: {data: {target: ANY_SERVICE}} }}, 20 | {provide: 'target', useValue: ANY_SERVICE}, 21 | {provide: 'template', useValue: ANY_SERVICE}, 22 | ] 23 | }) 24 | .compileComponents(); 25 | }); 26 | 27 | beforeEach(() => { 28 | fixture = TestBed.createComponent(TemplateCreateComponent); 29 | component = fixture.componentInstance; 30 | fixture.detectChanges(); 31 | }); 32 | 33 | it('should create', () => { 34 | expect(component).toBeTruthy(); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/router-compose/compose-icontabs-page/compose-icontabs-page.component.html: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/router-compose/compose-icontabs-page/compose-icontabs-page.component.scss: -------------------------------------------------------------------------------- 1 | .icon-tabs { 2 | 3 | width: 100%; 4 | text-align: center; 5 | position: relative; 6 | height: 3.5rem; 7 | margin-top: -1rem; 8 | a { 9 | margin: 5px; 10 | } 11 | } -------------------------------------------------------------------------------- /apps/naris/src/app/pages/router-compose/compose-icontabs-page/compose-icontabs-page.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ComposeIcontabsPageComponent } from './compose-icontabs-page.component'; 4 | 5 | describe('ComposeIcontabsPageComponent', () => { 6 | let component: ComposeIcontabsPageComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ComposeIcontabsPageComponent], 12 | }).compileComponents(); 13 | 14 | fixture = TestBed.createComponent(ComposeIcontabsPageComponent); 15 | component = fixture.componentInstance; 16 | fixture.detectChanges(); 17 | }); 18 | 19 | it('should create', () => { 20 | expect(component).toBeTruthy(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/router-compose/compose-one-page/compose-one-page.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | 6 |
7 |
8 |
9 | 10 | 11 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/router-compose/compose-one-page/compose-one-page.component.scss: -------------------------------------------------------------------------------- 1 | .player-container { 2 | background: #fff; 3 | margin: 0 auto; 4 | width: auto; 5 | position: absolute; 6 | top: 50%; 7 | right: 20px; 8 | left: 20px; 9 | z-index: 1; 10 | cursor: default; 11 | transform: translateY(-50%); 12 | 13 | &-width { 14 | max-width: 960px; 15 | } 16 | 17 | .player-wrapper { 18 | display: block; 19 | box-shadow: 0 1px 2px -2px rgb(0 0 0 / 16%), 0 3px 6px 0 rgb(0 0 0 / 12%), 0 5px 12px 4px rgb(0 0 0 / 9%); 20 | } 21 | 22 | @media screen and (min-width: 768px) { 23 | .player-wrapper { 24 | height: 540px; 25 | } 26 | } 27 | 28 | @media screen and (max-width: 768px) { 29 | .player-wrapper { 30 | height: 320px; 31 | 32 | } 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/router-compose/compose-one-page/compose-one-page.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpClientTestingModule } from '@angular/common/http/testing'; 2 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { RouterTestingModule } from '@angular/router/testing'; 4 | import { NzMessageService } from 'ng-zorro-antd/message'; 5 | 6 | import { ComposeOnePageComponent } from './compose-one-page.component'; 7 | 8 | class MockNzMessageService { 9 | error(msg: string): void { 10 | // empty 11 | } 12 | 13 | success(msg: string): void { 14 | // empty 15 | } 16 | } 17 | describe('ComposeOnePageComponent', () => { 18 | let component: ComposeOnePageComponent; 19 | let fixture: ComponentFixture; 20 | 21 | beforeEach(async () => { 22 | await TestBed.configureTestingModule({ 23 | declarations: [ ComposeOnePageComponent ], 24 | imports: [ 25 | HttpClientTestingModule, 26 | RouterTestingModule, 27 | ], 28 | providers: [ 29 | {provide: NzMessageService, useClass: MockNzMessageService} 30 | ] 31 | }) 32 | .compileComponents(); 33 | }); 34 | 35 | beforeEach(() => { 36 | fixture = TestBed.createComponent(ComposeOnePageComponent); 37 | component = fixture.componentInstance; 38 | fixture.detectChanges(); 39 | }); 40 | 41 | it('should create', () => { 42 | expect(component).toBeTruthy(); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/router-compose/compose-one-page/compose-one-page.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnDestroy, OnInit } from '@angular/core'; 2 | import { ActivatedRoute, Router } from '@angular/router'; 3 | import { MixedBusService } from '@soer/mixed-bus'; 4 | import { NzMessageService } from 'ng-zorro-antd/message'; 5 | import { ComposePage } from '../compose-page'; 6 | 7 | @Component({ 8 | selector: 'soer-compose-one-page', 9 | templateUrl: './compose-one-page.component.html', 10 | styleUrls: ['./compose-one-page.component.scss'], 11 | changeDetection: ChangeDetectionStrategy.OnPush 12 | }) 13 | export class ComposeOnePageComponent extends ComposePage implements OnInit, OnDestroy { 14 | 15 | constructor( 16 | bus$: MixedBusService, 17 | router: Router, 18 | route: ActivatedRoute, 19 | message: NzMessageService, 20 | cdp: ChangeDetectorRef 21 | ) { 22 | super(bus$, router, route, message, cdp); 23 | } 24 | 25 | ngOnInit(): void { 26 | this.composeInit(); 27 | } 28 | 29 | ngOnDestroy(): void { 30 | this.composeDestroy(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/router-compose/compose-tab-page/compose-tab-page.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{tab.title}} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/router-compose/compose-tab-page/compose-tab-page.component.scss: -------------------------------------------------------------------------------- 1 | nz-tabset { 2 | position: sticky; 3 | top: 0; 4 | background: white; 5 | z-index: 5; 6 | ::ng-deep .ant-tabs-nav { 7 | margin: 0 0 2px 0; 8 | } 9 | } 10 | 11 | 12 | .popup-container { 13 | background: #fff; 14 | margin: 0 auto; 15 | width: auto; 16 | position: absolute; 17 | z-index: 1; 18 | cursor: default; 19 | 20 | &-width { 21 | max-width: 960px; 22 | } 23 | 24 | .popup-wrapper { 25 | display: block; 26 | box-shadow: 0 1px 2px -2px rgb(0 0 0 / 16%), 0 3px 6px 0 rgb(0 0 0 / 12%), 0 5px 12px 4px rgb(0 0 0 / 9%); 27 | } 28 | } 29 | 30 | @media screen and (min-width: 768px) { 31 | .popup-container { 32 | top: 50%; 33 | right: 20px; 34 | left: 20px; 35 | transform: translateY(-50%); 36 | 37 | .popup-wrapper { 38 | height: 540px; 39 | } 40 | } 41 | } 42 | 43 | @media screen and (max-width: 768px) { 44 | .popup-container { 45 | top: 0; 46 | right: 0; 47 | left: 0; 48 | height: 100%; 49 | 50 | .popup-wrapper { 51 | height: 100%; 52 | } 53 | } 54 | } 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/router-compose/compose-tab-page/compose-tab-page.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { HttpClientTestingModule } from '@angular/common/http/testing'; 2 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { RouterTestingModule } from '@angular/router/testing'; 4 | import { NzMessageService } from 'ng-zorro-antd/message'; 5 | 6 | import { ComposeTabPageComponent } from './compose-tab-page.component'; 7 | 8 | class MockNzMessageService { 9 | error(msg: string): void { 10 | // empty 11 | } 12 | 13 | success(msg: string): void { 14 | // empty 15 | } 16 | } 17 | describe('ComposeTabPageComponent', () => { 18 | let component: ComposeTabPageComponent; 19 | let fixture: ComponentFixture; 20 | 21 | beforeEach(async () => { 22 | await TestBed.configureTestingModule({ 23 | declarations: [ ComposeTabPageComponent ], 24 | imports: [ 25 | HttpClientTestingModule, 26 | RouterTestingModule, 27 | ], 28 | providers: [ 29 | {provide: NzMessageService, useClass: MockNzMessageService} 30 | ] 31 | }) 32 | .compileComponents(); 33 | }); 34 | 35 | beforeEach(() => { 36 | fixture = TestBed.createComponent(ComposeTabPageComponent); 37 | component = fixture.componentInstance; 38 | fixture.detectChanges(); 39 | }); 40 | 41 | it('should create', () => { 42 | expect(component).toBeTruthy(); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/router-compose/router-compose.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { ComposeOnePageComponent } from './compose-one-page/compose-one-page.component'; 4 | import { ComposeTabPageComponent } from './compose-tab-page/compose-tab-page.component'; 5 | import { RouterModule } from '@angular/router'; 6 | import { DumbModule } from '../dumb/dumb.module'; 7 | import { NzTabsModule } from 'ng-zorro-antd/tabs'; 8 | import { NzLayoutModule } from 'ng-zorro-antd/layout'; 9 | import { NzGridModule } from 'ng-zorro-antd/grid'; 10 | import { ComposeIcontabsPageComponent } from './compose-icontabs-page/compose-icontabs-page.component'; 11 | import { NzIconModule } from 'ng-zorro-antd/icon'; 12 | import { NzButtonModule } from 'ng-zorro-antd/button'; 13 | 14 | @NgModule({ 15 | declarations: [ 16 | ComposeOnePageComponent, 17 | ComposeTabPageComponent, 18 | ComposeIcontabsPageComponent, 19 | ], 20 | imports: [ 21 | CommonModule, 22 | NzTabsModule, 23 | NzLayoutModule, 24 | NzGridModule, 25 | DumbModule, 26 | RouterModule, 27 | NzIconModule, 28 | NzButtonModule 29 | ], 30 | exports: [[ComposeOnePageComponent, ComposeTabPageComponent, ComposeIcontabsPageComponent]], 31 | }) 32 | export class RouterComposeModule {} 33 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/soer-components/soer-components.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { NzButtonModule } from 'ng-zorro-antd/button'; 4 | import { NzCardModule } from 'ng-zorro-antd/card'; 5 | import { NzGridModule } from 'ng-zorro-antd/grid'; 6 | import { NzIconModule } from 'ng-zorro-antd/icon'; 7 | import { NzLayoutModule } from 'ng-zorro-antd/layout'; 8 | import { TopicsListComponent } from './topics-list/topics-list.component'; 9 | 10 | 11 | 12 | @NgModule({ 13 | declarations: [TopicsListComponent], 14 | imports: [ 15 | CommonModule, 16 | NzButtonModule, 17 | NzLayoutModule, 18 | NzGridModule, 19 | NzIconModule, 20 | NzCardModule 21 | ], 22 | exports: [TopicsListComponent] 23 | }) 24 | export class SoerComponentsModule { } 25 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/soer-components/topics-list/topics-list.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 6 |

{{topic.title}}

7 |
8 | 9 |
10 |
11 |
12 | 13 | 14 |
15 | Нет данных 16 |
17 |
18 | скачать 19 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/soer-components/topics-list/topics-list.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/app/pages/soer-components/topics-list/topics-list.component.scss -------------------------------------------------------------------------------- /apps/naris/src/app/pages/soer-components/topics-list/topics-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TopicsListComponent } from './topics-list.component'; 4 | 5 | describe('TopicsListComponent', () => { 6 | let component: TopicsListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ TopicsListComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(TopicsListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /apps/naris/src/app/pages/soer-components/topics-list/topics-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from '@angular/core'; 2 | 3 | 4 | 5 | @Component({ 6 | selector: 'soer-topics-list', 7 | templateUrl: './topics-list.component.html', 8 | styleUrls: ['./topics-list.component.scss'] 9 | }) 10 | export class TopicsListComponent implements OnInit { 11 | 12 | @Input() topics: {overview: string, title: string}[] = []; 13 | constructor() { } 14 | 15 | ngOnInit(): void { 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /apps/naris/src/app/services/application.models.ts: -------------------------------------------------------------------------------- 1 | export interface UserModel { 2 | id: number; 3 | role: string; 4 | email: string; 5 | } -------------------------------------------------------------------------------- /apps/naris/src/app/services/menu/MenuControl.class.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from "@angular/core"; 2 | import { IMenuControl } from "./menu.interfaces"; 3 | 4 | export class MenuControl implements IMenuControl{ 5 | public fire: EventEmitter> = new EventEmitter>(); 6 | constructor(public title: string, public icon: string, public cb: () => void) {} 7 | } -------------------------------------------------------------------------------- /apps/naris/src/app/services/menu/menu.const.ts: -------------------------------------------------------------------------------- 1 | import { MenuTree } from "./menu.interfaces"; 2 | 3 | 4 | export const MAIN_MENU: MenuTree = [ 5 | { link: 'overview', icon: 'rocket', title: 'Брифинг', isPro: false }, 6 | { 7 | icon: 'appstore', title: 'Развитие', children: [ 8 | { link: 'targets', icon: 'check-circle', title: 'Цели', isPro: false }, 9 | { link: 'workbook', icon: 'solution', title: 'Конспекты', isPro: false }, 10 | { link: 'qa', icon: 'question', title: 'Вопрос ответ', isPro: false }, 11 | ], isPro: false 12 | }, 13 | { 14 | icon: 'play-circle', title: 'Материалы', children: [ 15 | { link: 'streams', icon: 'play-circle', title: 'Стримы', isPro: true }, 16 | { link: 'workshops', icon: 'experiment', title: 'Воркшопы', isPro: true }, 17 | { link: 'book', icon: 'book', title: 'Книга (главы)', isPro: true }, 18 | ], isPro: false 19 | }, 20 | { link: 'sources', icon: 'book', title: 'Исходники', isPro: true } 21 | ]; 22 | -------------------------------------------------------------------------------- /apps/naris/src/app/services/menu/menu.interfaces.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from "@angular/core"; 2 | 3 | export interface MenuItem { 4 | title: string; 5 | icon: string; 6 | link?: string; 7 | isPro: boolean; 8 | children?: MenuItem[]; 9 | } 10 | export type MenuTree = MenuItem[]; 11 | 12 | export interface IMenuControl { 13 | fire: EventEmitter>; 14 | title: string; 15 | icon: string; 16 | cb: () => void; 17 | } 18 | export type ApplicationMenu = [MenuTree | IMenuControl]; -------------------------------------------------------------------------------- /apps/naris/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/.gitkeep -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/android-chrome-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/android-chrome-144x144.png -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/android-chrome-192x192.png -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/android-chrome-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/android-chrome-256x256.png -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/android-chrome-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/android-chrome-36x36.png -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/android-chrome-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/android-chrome-384x384.png -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/android-chrome-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/android-chrome-48x48.png -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/android-chrome-512x512.png -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/android-chrome-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/android-chrome-72x72.png -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/android-chrome-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/android-chrome-96x96.png -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/apple-touch-icon.png -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/favicon-16x16.png -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/favicon-194x194.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/favicon-194x194.png -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/favicon-32x32.png -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/mstile-144x144.png -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/mstile-150x150.png -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/mstile-310x150.png -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/mstile-310x310.png -------------------------------------------------------------------------------- /apps/naris/src/assets/favicons/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/assets/favicons/mstile-70x70.png -------------------------------------------------------------------------------- /apps/naris/src/assets/soerpro.svg: -------------------------------------------------------------------------------- 1 | 2 | S0ER: PRO 3 | 4 | 5 | 6 | 7 | 8 | S0ER 9 | PRO 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /apps/naris/src/environments/constants.ts: -------------------------------------------------------------------------------- 1 | export const SLOW_TIMEOUT_INTERVAL = 5000; 2 | export const NORMAL_TIMEOUT_INTERVAL = 2500; 3 | /** 4 | * Интервал переодического опроса состояния со средней интенсивностью 5 | */ 6 | export const MEDIUM_TIMEOUT_INTERVAL = 1000; 7 | export const FAST_TIMEOUT_INTERVAL = 100; 8 | export const EMPTY_TIMEOUT = 0; -------------------------------------------------------------------------------- /apps/naris/src/environments/environment.interface.ts: -------------------------------------------------------------------------------- 1 | export interface EnvironmentInterface { 2 | host: string; 3 | production: boolean; 4 | googleAuthUrl: string; 5 | patreonAuthUrl: string; 6 | yandexAuthUrl: string; 7 | apiUrl: string; 8 | assetsUrl: string; 9 | privateAssetsUrl: string; 10 | payServiceUrl: string; 11 | } 12 | -------------------------------------------------------------------------------- /apps/naris/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | import { EnvironmentInterface } from './environment.interface'; 2 | 3 | const HOST = 'https://platform.soer.pro'; 4 | 5 | export const environment: EnvironmentInterface = { 6 | production: true, 7 | host: HOST, 8 | googleAuthUrl: HOST + '/api/auth/google', 9 | patreonAuthUrl: HOST + '/api/auth/patreon', 10 | yandexAuthUrl: HOST + '/api/auth/yandex', 11 | apiUrl: HOST + '/api/', 12 | assetsUrl: HOST + '/assets/', 13 | privateAssetsUrl: HOST + '/assets/private/', 14 | payServiceUrl: HOST + '/api/v2/seller' 15 | }; 16 | -------------------------------------------------------------------------------- /apps/naris/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | import { EnvironmentInterface } from './environment.interface'; 6 | 7 | // const HOST = 'http://localhost:4000'; 8 | const HOST = 'https://stage.s0er.ru'; 9 | //const HOST = 'http://api.soer'; 10 | export const environment: EnvironmentInterface = { 11 | production: false, 12 | host: HOST, 13 | googleAuthUrl: HOST + '/api/auth/google', 14 | patreonAuthUrl: HOST + '/api/auth/patreon', 15 | yandexAuthUrl: HOST + '/api/auth/yandex', 16 | apiUrl: HOST + '/api/', 17 | assetsUrl: HOST + '/assets/', 18 | privateAssetsUrl: HOST + '/assets/private/', 19 | payServiceUrl: HOST + '/api/v2/seller' 20 | }; 21 | 22 | /* 23 | * For easier debugging in development mode, you can import the following file 24 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 25 | * 26 | * This import should be commented out in production mode because it will have a negative impact 27 | * on performance if an error is thrown. 28 | */ 29 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 30 | -------------------------------------------------------------------------------- /apps/naris/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/apps/naris/src/favicon.ico -------------------------------------------------------------------------------- /apps/naris/src/icons-provider.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { NZ_ICONS, NzIconModule } from 'ng-zorro-antd/icon'; 3 | 4 | import { 5 | MenuFoldOutline, 6 | MenuUnfoldOutline, 7 | FormOutline, 8 | DashboardOutline 9 | } from '@ant-design/icons-angular/icons'; 10 | 11 | const icons = [MenuFoldOutline, MenuUnfoldOutline, DashboardOutline, FormOutline]; 12 | 13 | @NgModule({ 14 | imports: [NzIconModule], 15 | exports: [NzIconModule], 16 | providers: [ 17 | { provide: NZ_ICONS, useValue: icons } 18 | ] 19 | }) 20 | export class IconsProviderModule { 21 | } 22 | -------------------------------------------------------------------------------- /apps/naris/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Naris 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/naris/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic() 12 | .bootstrapModule(AppModule) 13 | .catch((err) => console.error(err)); 14 | -------------------------------------------------------------------------------- /apps/naris/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | .ant-popover-inner { 3 | max-height: 95vh; 4 | overflow-y: scroll; 5 | } 6 | -------------------------------------------------------------------------------- /apps/naris/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /apps/naris/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": [], 6 | "target": "es2020" 7 | }, 8 | "files": ["src/main.ts", "src/polyfills.ts"], 9 | "include": ["src/**/*.d.ts"], 10 | "exclude": ["**/*.test.ts", "**/*.spec.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /apps/naris/tsconfig.editor.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["**/*.ts"], 4 | "compilerOptions": { 5 | "types": ["jest", "node"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /apps/naris/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.app.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | }, 12 | { 13 | "path": "./tsconfig.editor.json" 14 | } 15 | ], 16 | "compilerOptions": { 17 | "forceConsistentCasingInFileNames": true, 18 | "strict": true, 19 | "noImplicitOverride": true, 20 | "noPropertyAccessFromIndexSignature": true, 21 | "noImplicitReturns": true, 22 | "noFallthroughCasesInSwitch": true, 23 | "target": "es2020" 24 | }, 25 | "angularCompilerOptions": { 26 | "strictInjectionParameters": true, 27 | "strictInputAccessModifiers": true, 28 | "strictTemplates": true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /apps/naris/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | npm install && npm run build 3 | status=$? 4 | if test $status -ne 0 5 | then 6 | exit $status 7 | fi 8 | cd dist && jar -cvf front.war ./front 9 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | const { getJestProjects } = require('@nrwl/jest'); 2 | 3 | module.exports = { 4 | projects: getJestProjects(), 5 | }; 6 | -------------------------------------------------------------------------------- /jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nrwl/jest/preset'); 2 | 3 | module.exports = { 4 | ...nxPreset, 5 | testEnvironment: 'jsdom', 6 | moduleNameMapper: { 7 | '@soer/sr-auth': '/../../libs/sr-auth/src/index.ts', 8 | '@soer/mixed-bus': '/../../libs/mixed-bus/src/index.ts', 9 | '@soer/sr-dto': '/../../libs/sr-dto/src/index.ts', 10 | '@soer/sr-url-builder': '/../../libs/sr-url-builder/src/index.ts', 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /libs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/libs/.gitkeep -------------------------------------------------------------------------------- /libs/mixed-bus/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | -------------------------------------------------------------------------------- /libs/mixed-bus/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@nrwl/nx/angular", 9 | "plugin:@angular-eslint/template/process-inline-templates" 10 | ], 11 | "rules": { 12 | "@angular-eslint/directive-selector": [ 13 | "error", 14 | { 15 | "type": "attribute", 16 | "prefix": "soer", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "soer", 25 | "style": "kebab-case" 26 | } 27 | ] 28 | } 29 | }, 30 | { 31 | "files": ["*.html"], 32 | "extends": ["plugin:@nrwl/nx/angular-template"], 33 | "rules": {} 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /libs/mixed-bus/README.md: -------------------------------------------------------------------------------- 1 | # mixed-bus 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test mixed-bus` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /libs/mixed-bus/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'mixed-bus', 3 | preset: '../../jest.preset.js', 4 | setupFilesAfterEnv: ['/src/test-setup.ts'], 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | stringifyContentPathRegex: '\\.(html|svg)$', 9 | }, 10 | }, 11 | coverageDirectory: '../../coverage/libs/mixed-bus', 12 | transform: { 13 | '^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular', 14 | }, 15 | transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], 16 | snapshotSerializers: [ 17 | 'jest-preset-angular/build/serializers/no-ng-attributes', 18 | 'jest-preset-angular/build/serializers/ng-snapshot', 19 | 'jest-preset-angular/build/serializers/html-comment', 20 | ], 21 | }; 22 | -------------------------------------------------------------------------------- /libs/mixed-bus/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/mixed-bus.module'; 2 | export * from './lib/mixed-bus.service'; 3 | export * from './lib/interfaces/mixed-bus.interface' 4 | export * from './lib/mixed-bus.helpers' -------------------------------------------------------------------------------- /libs/mixed-bus/src/lib/interfaces/mixed-bus.interface.ts: -------------------------------------------------------------------------------- 1 | 2 | export type BusKey = {[key: string]: any}; 3 | export type BusKeys = {[key: string]: T}; 4 | export type BusMessageParams = {[param: string]: any}; 5 | 6 | export type BusEmitter = {sid: symbol, schema: T, key?: BusKey}; 7 | 8 | export const ANY_SERVICE: BusEmitter = {sid: Symbol('AnyService'), schema: {}}; 9 | 10 | /** 11 | * EVENTS 12 | * события используются для информирования о состоянии команды в начале, 13 | * середине и конце выполнения 14 | */ 15 | export class BusEvent { 16 | constructor(public owner: BusEmitter = ANY_SERVICE, public payload: any = {}, public params: BusMessageParams = {}) {} 17 | } 18 | 19 | /** 20 | * COMMANDS 21 | * Команды используются для инициирования действия 22 | */ 23 | export class BusCommand { 24 | constructor(public owner: BusEmitter = ANY_SERVICE, public payload: any = {}, public params: BusMessageParams = {} ) {} 25 | } 26 | 27 | /** 28 | * ERRORS 29 | * Ошибки в процессе обработки событий 30 | */ 31 | export class BusError { 32 | constructor(public owner: BusEmitter = ANY_SERVICE, public errors: string[] ) {} 33 | } 34 | 35 | 36 | export type BusMessage = BusCommand | BusEvent; 37 | 38 | export interface IBus { 39 | channel: string; 40 | message: BusMessage | BusError; 41 | } 42 | -------------------------------------------------------------------------------- /libs/mixed-bus/src/lib/mixed-bus.helpers.ts: -------------------------------------------------------------------------------- 1 | import { BusEmitter, BusError, BusEvent, BusKey, BusMessage, BusMessageParams } from "./interfaces/mixed-bus.interface"; 2 | 3 | export function isBusMessage(message: BusMessage|BusError): message is BusMessage { 4 | return (message as BusMessage).payload !== undefined; 5 | } 6 | 7 | 8 | export function busEmitterFactory(owner: BusEmitter, params: BusMessageParams): BusEmitter { 9 | if (typeof params === 'object' && Object.keys(params).length > 0) { 10 | 11 | const key: BusKey = JSON.parse(JSON.stringify(params)); 12 | 13 | if (owner.key) { 14 | owner.key = {...owner.key, ...key}; 15 | Object.freeze(owner.key); 16 | return owner; 17 | } 18 | Object.freeze(key); 19 | return {...owner, key}; 20 | } 21 | 22 | return owner; 23 | } -------------------------------------------------------------------------------- /libs/mixed-bus/src/lib/mixed-bus.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { MixedBusService } from './mixed-bus.service'; 4 | 5 | @NgModule({ 6 | imports: [CommonModule], 7 | providers: [MixedBusService], 8 | declarations: [], 9 | }) 10 | export class MixedBusModule {} -------------------------------------------------------------------------------- /libs/mixed-bus/src/lib/mixed-bus.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { MixedBusService } from './mixed-bus.service'; 4 | 5 | describe('MixedBusService', () => { 6 | let service: MixedBusService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(MixedBusService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /libs/mixed-bus/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /libs/mixed-bus/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "forceConsistentCasingInFileNames": true, 15 | "strict": true, 16 | "noImplicitOverride": true, 17 | "noPropertyAccessFromIndexSignature": true, 18 | "noImplicitReturns": true, 19 | "noFallthroughCasesInSwitch": true, 20 | "target": "es2020" 21 | }, 22 | "angularCompilerOptions": { 23 | "strictInjectionParameters": true, 24 | "strictInputAccessModifiers": true, 25 | "strictTemplates": true 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /libs/mixed-bus/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "inlineSources": true, 8 | "types": [] 9 | }, 10 | "exclude": ["src/test-setup.ts", "**/*.spec.ts", "**/*.test.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/mixed-bus/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/sr-auth/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | -------------------------------------------------------------------------------- /libs/sr-auth/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@nrwl/nx/angular", 9 | "plugin:@angular-eslint/template/process-inline-templates" 10 | ], 11 | "rules": { 12 | "@angular-eslint/directive-selector": [ 13 | "error", 14 | { 15 | "type": "attribute", 16 | "prefix": "soer", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "soer", 25 | "style": "kebab-case" 26 | } 27 | ] 28 | } 29 | }, 30 | { 31 | "files": ["*.html"], 32 | "extends": ["plugin:@nrwl/nx/angular-template"], 33 | "rules": {} 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /libs/sr-auth/README.md: -------------------------------------------------------------------------------- 1 | # sr-auth 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test sr-auth` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /libs/sr-auth/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'sr-auth', 3 | preset: '../../jest.preset.js', 4 | setupFilesAfterEnv: ['/src/test-setup.ts'], 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | stringifyContentPathRegex: '\\.(html|svg)$', 9 | }, 10 | }, 11 | coverageDirectory: '../../coverage/libs/sr-auth', 12 | transform: { 13 | '^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular', 14 | }, 15 | transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], 16 | snapshotSerializers: [ 17 | 'jest-preset-angular/build/serializers/no-ng-attributes', 18 | 'jest-preset-angular/build/serializers/ng-snapshot', 19 | 'jest-preset-angular/build/serializers/html-comment', 20 | ], 21 | }; 22 | -------------------------------------------------------------------------------- /libs/sr-auth/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/sr-auth.module'; 2 | export * from './lib/services/auth.service'; 3 | export * from './lib/guards/auth.guard'; 4 | export * from './lib/interceptors/auth-interceptor.interceptor'; 5 | export * from './lib/interfaces/auth-options.interface'; 6 | export * from './lib/interfaces/jwt.models'; 7 | export * from './lib/auth.helpers' 8 | export const AUTH_ID = Symbol('Auth'); -------------------------------------------------------------------------------- /libs/sr-auth/src/lib/auth.helpers.ts: -------------------------------------------------------------------------------- 1 | import { BusMessage } from "@soer/mixed-bus"; 2 | import { map, Observable } from "rxjs"; 3 | import { EmptyJWTModel, JWTModel } from "./interfaces/jwt.models"; 4 | import { OK } from "@soer/sr-dto"; 5 | 6 | export function authUserInfo(messages$: Observable): Observable { 7 | return messages$.pipe(map( (data: BusMessage|null) => { 8 | let result: JWTModel = EmptyJWTModel; 9 | if (data?.payload?.status === OK) { 10 | result = data?.payload.items.pop() as JWTModel; 11 | } 12 | return result; 13 | }) 14 | ); 15 | } -------------------------------------------------------------------------------- /libs/sr-auth/src/lib/guards/auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router'; 3 | import { Observable } from 'rxjs'; 4 | import { AuthService } from '../services/auth.service'; 5 | 6 | 7 | @Injectable({ 8 | providedIn: 'root' 9 | }) 10 | export class AuthGuard implements CanActivate { 11 | constructor(private auth: AuthService) {} 12 | 13 | canActivate( 14 | route: ActivatedRouteSnapshot, 15 | state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree { 16 | // TODO: сделать обновление cookie когда грузятся модули, которые могут использовать эти куки 17 | this.auth.checkCookieAuth(); 18 | return !!this.auth.token; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /libs/sr-auth/src/lib/interfaces/auth-options.interface.ts: -------------------------------------------------------------------------------- 1 | import { BusEmitter } from "@soer/mixed-bus"; 2 | 3 | export interface AuthEmitter extends BusEmitter { 4 | sid: symbol; 5 | schema: { 6 | cookieApi: string; 7 | renewApi: string; 8 | }; 9 | } -------------------------------------------------------------------------------- /libs/sr-auth/src/lib/interfaces/jwt.models.ts: -------------------------------------------------------------------------------- 1 | export interface JWTModel { 2 | id: number; 3 | email: string; 4 | role: string; 5 | expired?: Date; 6 | namespaces?: any[]; 7 | iat: number; 8 | exp: number; 9 | } 10 | 11 | 12 | export const EmptyJWTModel: JWTModel = { 13 | id: -1, 14 | email: '', 15 | role: 'GUEST', 16 | iat: 0, 17 | exp: 0 18 | } -------------------------------------------------------------------------------- /libs/sr-auth/src/lib/sr-auth.module.ts: -------------------------------------------------------------------------------- 1 | import { ModuleWithProviders, NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { AuthService } from './services/auth.service'; 4 | import { AuthEmitter } from './interfaces/auth-options.interface'; 5 | import { AuthGuard } from './guards/auth.guard'; 6 | 7 | @NgModule({ 8 | imports: [CommonModule], 9 | providers: [ 10 | AuthService 11 | ] 12 | }) 13 | export class SrAuthModule { 14 | static forRoot(options: AuthEmitter): ModuleWithProviders { 15 | return { 16 | ngModule: SrAuthModule, 17 | providers: [ 18 | AuthGuard, 19 | { 20 | provide: 'AuthServiceConfig', 21 | useValue: options 22 | } 23 | ] 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /libs/sr-auth/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /libs/sr-auth/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "forceConsistentCasingInFileNames": true, 15 | "strict": true, 16 | "noImplicitOverride": true, 17 | "noPropertyAccessFromIndexSignature": true, 18 | "noImplicitReturns": true, 19 | "noFallthroughCasesInSwitch": true, 20 | "target": "es2020" 21 | }, 22 | "angularCompilerOptions": { 23 | "strictInjectionParameters": true, 24 | "strictInputAccessModifiers": true, 25 | "strictTemplates": true 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /libs/sr-auth/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "inlineSources": true, 8 | "types": [] 9 | }, 10 | "exclude": ["src/test-setup.ts", "**/*.spec.ts", "**/*.test.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/sr-auth/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/sr-dto/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | -------------------------------------------------------------------------------- /libs/sr-dto/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@nrwl/nx/angular", 9 | "plugin:@angular-eslint/template/process-inline-templates" 10 | ], 11 | "rules": { 12 | "@angular-eslint/directive-selector": [ 13 | "error", 14 | { 15 | "type": "attribute", 16 | "prefix": "soer", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "soer", 25 | "style": "kebab-case" 26 | } 27 | ] 28 | } 29 | }, 30 | { 31 | "files": ["*.html"], 32 | "extends": ["plugin:@nrwl/nx/angular-template"], 33 | "rules": {} 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /libs/sr-dto/README.md: -------------------------------------------------------------------------------- 1 | # sr-dto 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test sr-dto` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /libs/sr-dto/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'sr-dto', 3 | preset: '../../jest.preset.js', 4 | setupFilesAfterEnv: ['/src/test-setup.ts'], 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | stringifyContentPathRegex: '\\.(html|svg)$', 9 | }, 10 | }, 11 | coverageDirectory: '../../coverage/libs/sr-dto', 12 | transform: { 13 | '^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular', 14 | }, 15 | transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], 16 | snapshotSerializers: [ 17 | 'jest-preset-angular/build/serializers/no-ng-attributes', 18 | 'jest-preset-angular/build/serializers/ng-snapshot', 19 | 'jest-preset-angular/build/serializers/html-comment', 20 | ], 21 | }; 22 | -------------------------------------------------------------------------------- /libs/sr-dto/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/sr-dto.module'; 2 | export * from './lib/interfaces/crud.interface'; 3 | export * from './lib/interfaces/dto.pack.interface'; 4 | export * from './lib/services/data-store.service'; 5 | export * from './lib/services/store.crud.service'; 6 | export * from './lib/bus-messages/bus.messages'; 7 | export * from './lib/dto.helpers'; 8 | export * from './lib/interfaces/serialize-json.model'; -------------------------------------------------------------------------------- /libs/sr-dto/src/lib/dto.pipes.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import { DtoPack } from './interfaces/dto.pack.interface'; 3 | import { SerializedJsonModel } from './interfaces/serialize-json.model'; 4 | 5 | @Pipe({ 6 | name: 'dtoLastItem' 7 | }) 8 | export class DtoLastItemPipe implements PipeTransform { 9 | 10 | transform(dto: DtoPack | null): T|null { 11 | if (dto?.items && dto.items.length) { 12 | return dto.items[dto.items.length - 1]; 13 | } 14 | return null; 15 | } 16 | 17 | } 18 | 19 | 20 | @Pipe({ 21 | name: 'deSerializeJSON' 22 | }) 23 | export class DeSerializeJsonPipe implements PipeTransform { 24 | 25 | transform(data: SerializedJsonModel | null): T|null { 26 | if (data?.json) { 27 | return JSON.parse(data.json) as T; 28 | } 29 | return null; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /libs/sr-dto/src/lib/interfaces/crud.interface.ts: -------------------------------------------------------------------------------- 1 | import { BusMessage } from "@soer/mixed-bus"; 2 | import { DtoPack } from "./dto.pack.interface"; 3 | 4 | export interface CRUD { 5 | create(msg: BusMessage): Promise>; 6 | read(msg: BusMessage): Promise>; 7 | update(msg: BusMessage): Promise>; 8 | delete(msg: BusMessage): Promise>; 9 | } 10 | -------------------------------------------------------------------------------- /libs/sr-dto/src/lib/interfaces/dto.pack.interface.ts: -------------------------------------------------------------------------------- 1 | export const OK = 'ok'; 2 | export const ERROR = 'error'; 3 | export const LOADING = 'loading'; 4 | export const UPDATE = 'update'; 5 | export const INIT = 'init'; 6 | 7 | export type DtoStatus = typeof INIT | typeof OK | typeof ERROR | typeof LOADING | typeof UPDATE; 8 | 9 | export interface DtoPack { 10 | status: DtoStatus; 11 | items: T[]; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /libs/sr-dto/src/lib/interfaces/serialize-json.model.ts: -------------------------------------------------------------------------------- 1 | export interface SerializedJsonModel { 2 | id: number; 3 | json: string; 4 | namespace: string; 5 | author_email: string; 6 | accessTag: string; 7 | createdAt: Date; 8 | updatedAt: Date; 9 | } -------------------------------------------------------------------------------- /libs/sr-dto/src/lib/services/resolve-read-emitter.service.ts: -------------------------------------------------------------------------------- 1 | import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router'; 2 | import { ANT_ICON_ANGULAR_CONSOLE_PREFIX } from '@ant-design/icons-angular'; 3 | import { busEmitterFactory, MixedBusService } from '@soer/mixed-bus'; 4 | import { of } from 'rxjs'; 5 | import { first } from 'rxjs/operators'; 6 | import { ChangeDataEvent, CommandRead } from '../bus-messages/bus.messages'; 7 | import { CRUDBusEmitter } from '../sr-dto.module'; 8 | 9 | export class ResolveReadEmitterService implements Resolve { 10 | 11 | constructor(private bus$: MixedBusService, private owner: CRUDBusEmitter) { } 12 | 13 | resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { 14 | const owner = busEmitterFactory(this.owner, route.params); 15 | const wnd = (window as any); 16 | wnd.resolvedEmitters = wnd.resolvedEmitters || {}; 17 | wnd.resolvedEmitters[owner.sid.toString()] = owner; 18 | this.bus$.publish(new CommandRead(owner)); 19 | //TODO: refactor toPromise to firstValueOf 20 | return of(owner).toPromise(); 21 | } 22 | } 23 | `` -------------------------------------------------------------------------------- /libs/sr-dto/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /libs/sr-dto/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "forceConsistentCasingInFileNames": true, 15 | "strict": true, 16 | "noImplicitOverride": true, 17 | "noPropertyAccessFromIndexSignature": true, 18 | "noImplicitReturns": true, 19 | "noFallthroughCasesInSwitch": true, 20 | "target": "es2020" 21 | }, 22 | "angularCompilerOptions": { 23 | "strictInjectionParameters": true, 24 | "strictInputAccessModifiers": true, 25 | "strictTemplates": true 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /libs/sr-dto/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "inlineSources": true, 8 | "types": [] 9 | }, 10 | "exclude": ["src/test-setup.ts", "**/*.spec.ts", "**/*.test.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/sr-dto/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/sr-editor/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@nrwl/nx/angular", 9 | "plugin:@angular-eslint/template/process-inline-templates" 10 | ], 11 | "rules": { 12 | "@angular-eslint/directive-selector": [ 13 | "error", 14 | { 15 | "type": "attribute", 16 | "prefix": "soer", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "soer", 25 | "style": "kebab-case" 26 | } 27 | ] 28 | } 29 | }, 30 | { 31 | "files": ["*.html"], 32 | "extends": ["plugin:@nrwl/nx/angular-template"], 33 | "rules": {} 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /libs/sr-editor/README.md: -------------------------------------------------------------------------------- 1 | # sr-editor 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test sr-editor` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /libs/sr-editor/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'sr-editor', 4 | preset: '../../jest.preset.js', 5 | setupFilesAfterEnv: ['/src/test-setup.ts'], 6 | globals: { 7 | 'ts-jest': { 8 | tsconfig: '/tsconfig.spec.json', 9 | stringifyContentPathRegex: '\\.(html|svg)$', 10 | }, 11 | }, 12 | coverageDirectory: '../../coverage/libs/sr-editor', 13 | transform: { 14 | '^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular', 15 | }, 16 | transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], 17 | snapshotSerializers: [ 18 | 'jest-preset-angular/build/serializers/no-ng-attributes', 19 | 'jest-preset-angular/build/serializers/ng-snapshot', 20 | 'jest-preset-angular/build/serializers/html-comment', 21 | ], 22 | }; 23 | -------------------------------------------------------------------------------- /libs/sr-editor/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/sr-editor.module'; 2 | export * from './lib/interfaces/document.model'; -------------------------------------------------------------------------------- /libs/sr-editor/src/lib/blocks/block-editor/block-editor.component.scss: -------------------------------------------------------------------------------- 1 | .markdown-block { 2 | 3 | min-height: 2.5rem; 4 | width: 100%; 5 | padding: 0.5rem; 6 | border: 1px solid gray; 7 | background-color: rgb(247, 247, 247); 8 | } 9 | @media screen and (min-width: 768px) { 10 | .row { 11 | flex-direction: row; 12 | } 13 | 14 | .markdown-block { 15 | margin: 0.2rem 1rem; 16 | } 17 | } 18 | @media screen and (max-width: 768px) { 19 | .row { 20 | flex-direction: column; 21 | } 22 | .markdown-block { 23 | margin: 0; 24 | } 25 | 26 | } 27 | 28 | .row { 29 | display: flex; 30 | .info { 31 | flex-grow: 0; 32 | } 33 | .edit { 34 | flex-basis: 100%; 35 | glex-grow: 1; 36 | } 37 | .help { 38 | font-size: 0.7rem; 39 | font-style: italic; 40 | color: gray; 41 | } 42 | } -------------------------------------------------------------------------------- /libs/sr-editor/src/lib/blocks/block-editor/block-editor.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { BlockEditorComponent } from './block-editor.component'; 4 | 5 | describe('BlockEditorComponent', () => { 6 | let component: BlockEditorComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [BlockEditorComponent], 12 | }).compileComponents(); 13 | 14 | fixture = TestBed.createComponent(BlockEditorComponent); 15 | component = fixture.componentInstance; 16 | fixture.detectChanges(); 17 | }); 18 | 19 | it('should create', () => { 20 | expect(component).toBeTruthy(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /libs/sr-editor/src/lib/blocks/block-test/block-test.component.html: -------------------------------------------------------------------------------- 1 | {{question}} 2 | 3 |
    4 |
  • 5 | 9 |
  • 10 |
11 | 12 | 13 |

Не указан ни один вопрос

-------------------------------------------------------------------------------- /libs/sr-editor/src/lib/blocks/block-test/block-test.component.scss: -------------------------------------------------------------------------------- 1 | 2 | .quiz-questions-list { 3 | list-style: none; 4 | margin-top: 1em; 5 | } 6 | 7 | .quiz-question__label { 8 | font-size: 14px; 9 | display: inline-block; 10 | position: relative; 11 | cursor: pointer; 12 | } -------------------------------------------------------------------------------- /libs/sr-editor/src/lib/blocks/block-test/block-test.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { BlockTestComponent } from './block-test.component'; 4 | 5 | describe('BlockTestComponent', () => { 6 | let component: BlockTestComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [BlockTestComponent], 12 | }).compileComponents(); 13 | 14 | fixture = TestBed.createComponent(BlockTestComponent); 15 | component = fixture.componentInstance; 16 | fixture.detectChanges(); 17 | }); 18 | 19 | it('should create', () => { 20 | expect(component).toBeTruthy(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /libs/sr-editor/src/lib/blocks/block-test/block-test.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'soer-block-test', 5 | templateUrl: './block-test.component.html', 6 | styleUrls: ['./block-test.component.scss'], 7 | }) 8 | export class BlockTestComponent implements OnInit { 9 | @Input() text = ''; 10 | 11 | question = ''; 12 | answers: {answer: string, correct: boolean}[] = []; 13 | 14 | 15 | ngOnInit(): void { 16 | const blocks = this.text.split("\n\n"); 17 | const answersText = blocks.pop(); 18 | const question = blocks.join("\n\n"); 19 | 20 | if (answersText) { 21 | const answers = (answersText + '').split("\n").map(tmpAnswer => { 22 | const correct = tmpAnswer.substring(0, 1) === '+'; 23 | return {answer: tmpAnswer.substring(1), correct}; 24 | }); 25 | this.answers = answers; 26 | } 27 | 28 | this.question = question; 29 | 30 | 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /libs/sr-editor/src/lib/editor/editor.component.html: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /libs/sr-editor/src/lib/editor/editor.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/libs/sr-editor/src/lib/editor/editor.component.scss -------------------------------------------------------------------------------- /libs/sr-editor/src/lib/editor/editor.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { EditorComponent } from './editor.component'; 4 | 5 | describe('EditorComponent', () => { 6 | let component: EditorComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [EditorComponent], 12 | }).compileComponents(); 13 | 14 | fixture = TestBed.createComponent(EditorComponent); 15 | component = fixture.componentInstance; 16 | fixture.detectChanges(); 17 | }); 18 | 19 | it('should create', () => { 20 | expect(component).toBeTruthy(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /libs/sr-editor/src/lib/interfaces/document.model.ts: -------------------------------------------------------------------------------- 1 | export interface TextBlock { 2 | type: 'markdown' | 'test' | 'presentation', 3 | text: string; 4 | } 5 | export interface WorkbookModel { 6 | id?: number|null, 7 | question: string, 8 | text?: string, 9 | blocks: TextBlock[] 10 | 11 | } 12 | 13 | export const EMPTY_WORKBOOK: WorkbookModel = { 14 | id: null, 15 | question: '', 16 | blocks: [{text: '', type: 'markdown'}] 17 | } -------------------------------------------------------------------------------- /libs/sr-editor/src/lib/sr-editor.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { EditorComponent } from './editor/editor.component'; 4 | import { BlockEditorComponent } from './blocks/block-editor/block-editor.component'; 5 | import { MarkdownModule } from 'ngx-markdown'; 6 | import { FormsModule } from '@angular/forms'; 7 | import { TextareaAutoresizeDirective } from './textarea-autoresize.directive'; 8 | import { BlockTestComponent } from './blocks/block-test/block-test.component'; 9 | 10 | @NgModule({ 11 | imports: [CommonModule, MarkdownModule.forRoot(), FormsModule], 12 | declarations: [ 13 | EditorComponent, 14 | BlockEditorComponent, 15 | TextareaAutoresizeDirective, 16 | BlockTestComponent, 17 | ], 18 | exports: [EditorComponent], 19 | }) 20 | export class SrEditorModule {} 21 | -------------------------------------------------------------------------------- /libs/sr-editor/src/lib/textarea-autoresize.directive.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Directive, ElementRef, HostListener } from "@angular/core"; 3 | 4 | @Directive({ 5 | selector: "[soerAutoresize]" // Attribute selector 6 | }) 7 | export class TextareaAutoresizeDirective { 8 | @HostListener('input', ['$event.target']) 9 | onInput(): void { 10 | this.adjust(); 11 | } 12 | 13 | constructor(public element: ElementRef) { 14 | } 15 | 16 | ngOnInit(): void { 17 | if (this.element.nativeElement.scrollHeight) { 18 | setTimeout(() => this.adjust()); 19 | } 20 | } 21 | 22 | adjust(): void { 23 | const ta = this.element.nativeElement; 24 | this.element.nativeElement.style.height = '0'; 25 | this.element.nativeElement.style.height = this.element.nativeElement.scrollHeight + 10 + 'px'; 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /libs/sr-editor/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /libs/sr-editor/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "target": "es2020", 15 | "forceConsistentCasingInFileNames": true, 16 | "strict": true, 17 | "noImplicitOverride": true, 18 | "noPropertyAccessFromIndexSignature": true, 19 | "noImplicitReturns": true, 20 | "noFallthroughCasesInSwitch": true 21 | }, 22 | "angularCompilerOptions": { 23 | "enableI18nLegacyMessageIdFormat": false, 24 | "strictInjectionParameters": true, 25 | "strictInputAccessModifiers": true, 26 | "strictTemplates": true 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /libs/sr-editor/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "inlineSources": true, 8 | "types": [] 9 | }, 10 | "exclude": ["src/test-setup.ts", "**/*.spec.ts", "**/*.test.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/sr-editor/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/sr-url-builder/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | -------------------------------------------------------------------------------- /libs/sr-url-builder/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@nrwl/nx/angular", 9 | "plugin:@angular-eslint/template/process-inline-templates" 10 | ], 11 | "rules": { 12 | "@angular-eslint/directive-selector": [ 13 | "error", 14 | { 15 | "type": "attribute", 16 | "prefix": "soer", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "soer", 25 | "style": "kebab-case" 26 | } 27 | ] 28 | } 29 | }, 30 | { 31 | "files": ["*.html"], 32 | "extends": ["plugin:@nrwl/nx/angular-template"], 33 | "rules": {} 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /libs/sr-url-builder/README.md: -------------------------------------------------------------------------------- 1 | # sr-url-builder 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test sr-url-builder` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /libs/sr-url-builder/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'sr-url-builder', 3 | preset: '../../jest.preset.js', 4 | setupFilesAfterEnv: ['/src/test-setup.ts'], 5 | globals: { 6 | 'ts-jest': { 7 | tsconfig: '/tsconfig.spec.json', 8 | stringifyContentPathRegex: '\\.(html|svg)$', 9 | }, 10 | }, 11 | coverageDirectory: '../../coverage/libs/sr-url-builder', 12 | transform: { 13 | '^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular', 14 | }, 15 | transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], 16 | snapshotSerializers: [ 17 | 'jest-preset-angular/build/serializers/no-ng-attributes', 18 | 'jest-preset-angular/build/serializers/ng-snapshot', 19 | 'jest-preset-angular/build/serializers/html-comment', 20 | ], 21 | }; 22 | -------------------------------------------------------------------------------- /libs/sr-url-builder/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/sr-url-builder.module'; 2 | export * from './lib/services/url-builder.service' -------------------------------------------------------------------------------- /libs/sr-url-builder/src/lib/interfaces/url-builder.interface.ts: -------------------------------------------------------------------------------- 1 | export interface UrlBuilderOptions { 2 | apiRoot: string; 3 | } 4 | 5 | export interface UrlParam { 6 | [key: string]: number|string; 7 | } -------------------------------------------------------------------------------- /libs/sr-url-builder/src/lib/services/url-builder.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Injectable } from '@angular/core'; 2 | import { UrlBuilderOptions } from '../interfaces/url-builder.interface'; 3 | import { BusKey, BusMessageParams } from '@soer/mixed-bus'; 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class UrlBuilderService { 9 | constructor( 10 | @Inject('UrlBuilderServiceConfig') private options: UrlBuilderOptions 11 | ) { 12 | console.log('Builder start with ', options); 13 | } 14 | 15 | build(apiSuffix: string = '', key: BusKey = {}, routeParams: BusMessageParams = {}, urlParams: Record = {}): string { 16 | const urlSegments = apiSuffix.split('/').map(part => { 17 | if (part[0] === ':') { 18 | const keyName = part.substring(1); 19 | return ((key[keyName] === '?') ? routeParams[keyName] : key[keyName]) || ''; 20 | } 21 | return part; 22 | }).filter(value => !!value); 23 | 24 | 25 | 26 | const urlMappedParams = Object.keys(urlParams).map(paramName => { 27 | if (urlParams[paramName] === '?') { 28 | return key[paramName] ? `${paramName}=${key[paramName]}` : ''; 29 | } 30 | return `${paramName}=${urlParams[paramName]}`; 31 | }).filter(value => value !== ''); 32 | const urlResultParams = urlMappedParams.length ? `?${urlMappedParams.join('&')}` : ''; 33 | return `${this.options.apiRoot}${urlSegments.join('/')}${urlResultParams}`; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /libs/sr-url-builder/src/lib/sr-url-builder.module.ts: -------------------------------------------------------------------------------- 1 | import { ModuleWithProviders, NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { UrlBuilderOptions } from './interfaces/url-builder.interface'; 4 | 5 | 6 | @NgModule({ 7 | declarations: [], 8 | imports: [ 9 | CommonModule 10 | ] 11 | }) 12 | export class SrUrlBuilderModule { 13 | static forRoot(options: UrlBuilderOptions): ModuleWithProviders { 14 | return { 15 | ngModule: SrUrlBuilderModule, 16 | providers: [ 17 | { 18 | provide: 'UrlBuilderServiceConfig', 19 | useValue: options 20 | } 21 | ] 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /libs/sr-url-builder/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /libs/sr-url-builder/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "forceConsistentCasingInFileNames": true, 15 | "strict": true, 16 | "noImplicitOverride": true, 17 | "noPropertyAccessFromIndexSignature": true, 18 | "noImplicitReturns": true, 19 | "noFallthroughCasesInSwitch": true, 20 | "target": "es2020" 21 | }, 22 | "angularCompilerOptions": { 23 | "strictInjectionParameters": true, 24 | "strictInputAccessModifiers": true, 25 | "strictTemplates": true 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /libs/sr-url-builder/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "inlineSources": true, 8 | "types": [] 9 | }, 10 | "exclude": ["src/test-setup.ts", "**/*.spec.ts", "**/*.test.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/sr-url-builder/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /migrations.json: -------------------------------------------------------------------------------- 1 | { 2 | "migrations": [ 3 | { 4 | "cli": "nx", 5 | "version": "14.3.4-beta.1", 6 | "description": "Replace targetDependencies with targetDefaults", 7 | "implementation": "./src/migrations/update-14-3-4/create-target-defaults", 8 | "package": "nx", 9 | "name": "14.3.4-create-target-defaults" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "npmScope": "soer", 3 | "affected": { 4 | "defaultBase": "main" 5 | }, 6 | "cli": { 7 | "packageManager": "npm" 8 | }, 9 | "implicitDependencies": { 10 | "package.json": { 11 | "dependencies": "*", 12 | "devDependencies": "*" 13 | }, 14 | ".eslintrc.json": "*" 15 | }, 16 | "tasksRunnerOptions": { 17 | "default": { 18 | "runner": "@nrwl/workspace/tasks-runners/default", 19 | "options": { 20 | "cacheableOperations": ["build", "lint", "test", "e2e"] 21 | } 22 | } 23 | }, 24 | "generators": { 25 | "@nrwl/angular:application": { 26 | "style": "scss", 27 | "linter": "eslint", 28 | "unitTestRunner": "jest", 29 | "e2eTestRunner": "cypress" 30 | }, 31 | "@nrwl/angular:library": { 32 | "linter": "eslint", 33 | "unitTestRunner": "jest" 34 | }, 35 | "@nrwl/angular:component": { 36 | "style": "scss" 37 | } 38 | }, 39 | "defaultProject": "naris", 40 | "$schema": "./node_modules/nx/schemas/nx-schema.json", 41 | "targetDefaults": { 42 | "build": { 43 | "dependsOn": ["^build"] 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /publish.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | cd dist/apps && jar -cvf naris.war ./naris 4 | scp -P $SSH_PORT ./naris.war $SSH_USER@$SSH_HOST:$SSH_WWW_PATH/naris.war 5 | ssh -p $SSH_PORT -l $SSH_USER $SSH_HOST 'cd '$SSH_WWW_PATH'/ && jar -xvf naris.war' 6 | 7 | -------------------------------------------------------------------------------- /tools/generators/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soerdev/soer/c41d5d213104c6a92467e044247149b9b315fc7c/tools/generators/.gitkeep -------------------------------------------------------------------------------- /tools/tsconfig.tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "../dist/out-tsc/tools", 5 | "rootDir": ".", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": ["node"], 9 | "importHelpers": false 10 | }, 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "importHelpers": true, 11 | "target": "es2015", 12 | "module": "esnext", 13 | "lib": ["es2017", "dom"], 14 | "skipLibCheck": true, 15 | "skipDefaultLibCheck": true, 16 | "baseUrl": ".", 17 | "paths": { 18 | "@soer/mixed-bus": ["libs/mixed-bus/src/index.ts"], 19 | "@soer/sr-auth": ["libs/sr-auth/src/index.ts"], 20 | "@soer/sr-dto": ["libs/sr-dto/src/index.ts"], 21 | "@soer/sr-editor": ["libs/sr-editor/src/index.ts"], 22 | "@soer/sr-url-builder": ["libs/sr-url-builder/src/index.ts"] 23 | } 24 | }, 25 | "exclude": ["node_modules", "tmp"] 26 | } 27 | -------------------------------------------------------------------------------- /workshop/rest/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | tsconfigRootDir : __dirname, 6 | sourceType: 'module', 7 | }, 8 | plugins: ['@typescript-eslint/eslint-plugin'], 9 | extends: [ 10 | 'plugin:@typescript-eslint/recommended', 11 | 'plugin:prettier/recommended', 12 | ], 13 | root: true, 14 | env: { 15 | node: true, 16 | jest: true, 17 | }, 18 | ignorePatterns: ['.eslintrc.js'], 19 | rules: { 20 | '@typescript-eslint/interface-name-prefix': 'off', 21 | '@typescript-eslint/explicit-function-return-type': 'off', 22 | '@typescript-eslint/explicit-module-boundary-types': 'off', 23 | '@typescript-eslint/no-explicit-any': 'off', 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /workshop/rest/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | # compiled output 3 | /dist 4 | /node_modules 5 | 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | pnpm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | lerna-debug.log* 14 | 15 | # OS 16 | .DS_Store 17 | 18 | # Tests 19 | /coverage 20 | /.nyc_output 21 | 22 | # IDEs and editors 23 | /.idea 24 | .project 25 | .classpath 26 | .c9/ 27 | *.launch 28 | .settings/ 29 | *.sublime-workspace 30 | 31 | # IDE - VSCode 32 | .vscode/* 33 | !.vscode/settings.json 34 | !.vscode/tasks.json 35 | !.vscode/launch.json 36 | !.vscode/extensions.json 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /workshop/rest/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /workshop/rest/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/nest-cli", 3 | "collection": "@nestjs/schematics", 4 | "sourceRoot": "src" 5 | } 6 | -------------------------------------------------------------------------------- /workshop/rest/src/app.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | 5 | describe('AppController', () => { 6 | let appController: AppController; 7 | 8 | beforeEach(async () => { 9 | const app: TestingModule = await Test.createTestingModule({ 10 | controllers: [AppController], 11 | providers: [AppService], 12 | }).compile(); 13 | 14 | appController = app.get(AppController); 15 | }); 16 | 17 | describe('root', () => { 18 | it('should return "Hello World!"', () => { 19 | expect(appController.getHello()).toBe('Hello World!'); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /workshop/rest/src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common'; 2 | import { AppService } from './app.service'; 3 | 4 | @Controller() 5 | export class AppController { 6 | constructor(private readonly appService: AppService) {} 7 | 8 | @Get() 9 | getHello(): string { 10 | return this.appService.getHello(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /workshop/rest/src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | import { GroupsModule } from './groups/groups.module'; 5 | import { DocumentsModule } from './documents/documents.module'; 6 | 7 | @Module({ 8 | imports: [GroupsModule, DocumentsModule], 9 | controllers: [AppController], 10 | providers: [AppService], 11 | }) 12 | export class AppModule {} 13 | -------------------------------------------------------------------------------- /workshop/rest/src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | getHello(): string { 6 | return 'Hello World!'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /workshop/rest/src/documents/documents.api.http: -------------------------------------------------------------------------------- 1 | @collection = documents 2 | @version = v1 3 | @backend = http://localhost:3000 4 | 5 | // ------ Documents CRUD 6 | 7 | ### Create document 8 | # @name newDocument 9 | POST {{backend}}/api/{{version}}/{{collection}} 10 | Content-Type: application/json 11 | 12 | { 13 | "body": "Document {{$randomInt 0 100}}" 14 | } 15 | 16 | ### Get documents 17 | GET {{backend}}/api/{{version}}/{{collection}} 18 | 19 | ### Get document by id 20 | GET {{backend}}/api/{{version}}/{{collection}}/{{newDocument.response.body.id}} 21 | 22 | ### Delete document by id 23 | DELETE {{backend}}/api/{{version}}/{{collection}}/{{newDocument.response.body.id}} 24 | 25 | // ------ Errors 26 | 27 | 28 | // ------ Groups 29 | 30 | ### Create group 31 | # @name newGroup 32 | POST {{backend}}/api/{{version}}/groups 33 | Content-Type: application/json 34 | 35 | { 36 | "name": "Group{{$randomInt 0 100}}" 37 | } 38 | 39 | 40 | ### Create document with group 41 | # @name newDocument 42 | POST {{backend}}/api/{{version}}/{{collection}}?groupUrn={{newGroup.response.body.urn}} 43 | Content-Type: application/json 44 | 45 | { 46 | "body": "Document {{$randomInt 0 100}}" 47 | } 48 | 49 | ### Get documents by groupname 50 | GET {{backend}}/api/{{version}}/groups/{{newGroup.response.body.name}}/{{collection}} 51 | -------------------------------------------------------------------------------- /workshop/rest/src/documents/documents.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { DocumentsController } from './documents.controller'; 3 | import { DocumentsService } from './documents.service'; 4 | 5 | describe('DocumentsController', () => { 6 | let controller: DocumentsController; 7 | 8 | beforeEach(async () => { 9 | const module: TestingModule = await Test.createTestingModule({ 10 | controllers: [DocumentsController], 11 | providers: [DocumentsService], 12 | }).compile(); 13 | 14 | controller = module.get(DocumentsController); 15 | }); 16 | 17 | it('should be defined', () => { 18 | expect(controller).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /workshop/rest/src/documents/documents.controller.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Body, 3 | Controller, 4 | Delete, 5 | Get, 6 | Param, 7 | Post, 8 | Put, 9 | Query, 10 | } from '@nestjs/common'; 11 | import { DocumentsService } from './documents.service'; 12 | import { CreateDocumentDto } from './dto/create-document.dto'; 13 | import { UpdateDocumentDto } from './dto/update-document.dto'; 14 | 15 | @Controller('v1/documents') 16 | export class DocumentsController { 17 | constructor(private readonly documentsService: DocumentsService) {} 18 | 19 | @Post() 20 | create( 21 | @Query('groupUrn') groupUrn: string, 22 | @Body() createDocumentDto: CreateDocumentDto, 23 | ) { 24 | return this.documentsService.create(createDocumentDto, groupUrn); 25 | } 26 | 27 | @Get() 28 | findAll() { 29 | return this.documentsService.findAll(); 30 | } 31 | 32 | @Get(':id') 33 | findOne(@Param('id') id: string) { 34 | return this.documentsService.findOne(+id); 35 | } 36 | 37 | @Put(':id') 38 | update( 39 | @Param('id') id: string, 40 | @Body() updateDocumentDto: UpdateDocumentDto, 41 | ) { 42 | return this.documentsService.update(+id, updateDocumentDto); 43 | } 44 | 45 | @Delete(':id') 46 | remove(@Param('id') id: string) { 47 | return this.documentsService.remove(+id); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /workshop/rest/src/documents/documents.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { DocumentsService } from './documents.service'; 3 | import { DocumentsController } from './documents.controller'; 4 | 5 | @Module({ 6 | controllers: [DocumentsController], 7 | providers: [DocumentsService], 8 | exports: [DocumentsService], 9 | }) 10 | export class DocumentsModule {} 11 | -------------------------------------------------------------------------------- /workshop/rest/src/documents/dto/create-document.dto.ts: -------------------------------------------------------------------------------- 1 | export class CreateDocumentDto { 2 | readonly body: string; 3 | } 4 | -------------------------------------------------------------------------------- /workshop/rest/src/documents/dto/update-document.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types'; 2 | import { CreateDocumentDto } from './create-document.dto'; 3 | 4 | export class UpdateDocumentDto extends PartialType(CreateDocumentDto) { 5 | readonly body: string; 6 | } 7 | -------------------------------------------------------------------------------- /workshop/rest/src/documents/entities/document.entity.ts: -------------------------------------------------------------------------------- 1 | export class DocumentEntity { 2 | id: number; 3 | urn: string; 4 | body: string; 5 | groupUrn: null | string; 6 | } 7 | -------------------------------------------------------------------------------- /workshop/rest/src/groups/dto/create-group.dto.ts: -------------------------------------------------------------------------------- 1 | export class CreateGroupDto { 2 | readonly name: string; 3 | } 4 | -------------------------------------------------------------------------------- /workshop/rest/src/groups/dto/update-group.dto.ts: -------------------------------------------------------------------------------- 1 | import { PartialType } from '@nestjs/mapped-types'; 2 | import { CreateGroupDto } from './create-group.dto'; 3 | 4 | export class UpdateGroupDto extends PartialType(CreateGroupDto) { 5 | readonly name: string; 6 | } 7 | -------------------------------------------------------------------------------- /workshop/rest/src/groups/entities/group.entity.ts: -------------------------------------------------------------------------------- 1 | export class GroupEntity { 2 | id: number; 3 | urn: string; 4 | name: string; 5 | } 6 | -------------------------------------------------------------------------------- /workshop/rest/src/groups/groups.api.http: -------------------------------------------------------------------------------- 1 | @collection = groups 2 | @version = v1 3 | @backend = http://localhost:3000 4 | 5 | // ------ Documents CRUD 6 | 7 | ### Create group 8 | # @name newGroup 9 | POST {{backend}}/api/{{version}}/{{collection}} 10 | Content-Type: application/json 11 | 12 | { 13 | "body": "Document {{$randomInt 0 100}}" 14 | } 15 | 16 | ### Get groups 17 | GET {{backend}}/api/{{version}}/{{collection}} 18 | 19 | ### Get group by id 20 | GET {{backend}}/api/{{version}}/{{collection}}/{{newGroup.response.body.id}} 21 | 22 | ### Delete group by id 23 | DELETE {{backend}}/api/{{version}}/{{collection}}/{{newGroup.response.body.id}} 24 | 25 | // ------ Errors 26 | 27 | 28 | -------------------------------------------------------------------------------- /workshop/rest/src/groups/groups.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { GroupsController } from './groups.controller'; 3 | import { GroupsService } from './groups.service'; 4 | 5 | describe('GroupsController', () => { 6 | let controller: GroupsController; 7 | 8 | beforeEach(async () => { 9 | const module: TestingModule = await Test.createTestingModule({ 10 | controllers: [GroupsController], 11 | providers: [GroupsService], 12 | }).compile(); 13 | 14 | controller = module.get(GroupsController); 15 | }); 16 | 17 | it('should be defined', () => { 18 | expect(controller).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /workshop/rest/src/groups/groups.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GroupsService } from './groups.service'; 3 | import { GroupsController } from './groups.controller'; 4 | import { DocumentsModule } from '../documents/documents.module'; 5 | 6 | @Module({ 7 | imports: [DocumentsModule], 8 | controllers: [GroupsController], 9 | providers: [GroupsService], 10 | }) 11 | export class GroupsModule {} 12 | -------------------------------------------------------------------------------- /workshop/rest/src/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { AppModule } from './app.module'; 3 | 4 | async function bootstrap() { 5 | const app = await NestFactory.create(AppModule); 6 | app.setGlobalPrefix('/api'); 7 | await app.listen(3000); 8 | } 9 | bootstrap(); 10 | -------------------------------------------------------------------------------- /workshop/rest/test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { INestApplication } from '@nestjs/common'; 3 | import * as request from 'supertest'; 4 | import { AppModule } from './../src/app.module'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | beforeEach(async () => { 10 | const moduleFixture: TestingModule = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); 13 | 14 | app = moduleFixture.createNestApplication(); 15 | await app.init(); 16 | }); 17 | 18 | it('/ (GET)', () => { 19 | return request(app.getHttpServer()) 20 | .get('/') 21 | .expect(200) 22 | .expect('Hello World!'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /workshop/rest/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /workshop/rest/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /workshop/rest/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "es2017", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": false, 16 | "noImplicitAny": false, 17 | "strictBindCallApply": false, 18 | "forceConsistentCasingInFileNames": false, 19 | "noFallthroughCasesInSwitch": false 20 | } 21 | } 22 | --------------------------------------------------------------------------------