├── .gitignore ├── .idea └── vcs.xml ├── CONTAINERS.md ├── LICENSE ├── README.md ├── UI ├── .browserslistrc ├── .editorconfig ├── .gitignore ├── .vscode │ └── settings.json ├── Dockerfile ├── Dockerfile_no-npm ├── angular.json ├── e2e │ ├── protractor.conf.js │ ├── src │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.e2e.json ├── email │ ├── recovery.html │ └── registration.html ├── entrypoint.sh ├── frontend-envs.txt ├── nginx.conf ├── package-lock.json ├── package.json ├── src │ ├── .env │ ├── app │ │ ├── app-routing.module.ts │ │ ├── app.component.html │ │ ├── app.component.scss │ │ ├── app.component.ts │ │ ├── app.constants.ts │ │ ├── app.module.ts │ │ ├── app.util.ts │ │ ├── auth.config.ts │ │ ├── auth │ │ │ ├── already-registered │ │ │ │ ├── already-registered.component.html │ │ │ │ ├── already-registered.component.scss │ │ │ │ └── already-registered.component.ts │ │ │ ├── auth-routing.module.ts │ │ │ ├── auth-util.ts │ │ │ ├── auth.component.scss │ │ │ ├── auth.component.ts │ │ │ ├── auth.module.ts │ │ │ ├── auxiliary │ │ │ │ ├── auth-background │ │ │ │ │ ├── auth-background.component.html │ │ │ │ │ ├── auth-background.component.scss │ │ │ │ │ └── auth-background.component.ts │ │ │ │ ├── auth-error-message │ │ │ │ │ ├── auth-error-message.component.html │ │ │ │ │ ├── auth-error-message.component.scss │ │ │ │ │ └── auth-error-message.component.ts │ │ │ │ ├── auth-logo │ │ │ │ │ ├── auth-logo.component.html │ │ │ │ │ └── auth-logo.component.ts │ │ │ │ ├── auth-password-input │ │ │ │ │ ├── auth-password-input.component.html │ │ │ │ │ ├── auth-password-input.component.scss │ │ │ │ │ └── auth-password-input.component.ts │ │ │ │ ├── confirm-password-validator.ts │ │ │ │ ├── password-form-controls.ts │ │ │ │ ├── regexes.ts │ │ │ │ └── validate-message │ │ │ │ │ ├── validate-message.component.html │ │ │ │ │ ├── validate-message.component.scss │ │ │ │ │ └── validate-message.component.ts │ │ │ ├── link-expired │ │ │ │ ├── link-expired.component.html │ │ │ │ ├── link-expired.component.scss │ │ │ │ └── link-expired.component.ts │ │ │ ├── recover-password │ │ │ │ ├── recover-password.component.html │ │ │ │ ├── recover-password.component.scss │ │ │ │ └── recover-password.component.ts │ │ │ ├── reset-password │ │ │ │ ├── reset-password.component.html │ │ │ │ ├── reset-password.component.scss │ │ │ │ └── reset-password.component.ts │ │ │ ├── sign-in │ │ │ │ ├── sign-in.component.html │ │ │ │ ├── sign-in.component.scss │ │ │ │ └── sign-in.component.ts │ │ │ └── sign-out │ │ │ │ ├── sign-out.component.html │ │ │ │ ├── sign-out.component.scss │ │ │ │ └── sign-out.component.ts │ │ ├── cdm │ │ │ ├── cdm-routing.module.ts │ │ │ ├── cdm.component.html │ │ │ ├── cdm.component.scss │ │ │ ├── cdm.component.ts │ │ │ ├── cdm.module.ts │ │ │ ├── code-mapping │ │ │ │ ├── code-mapping-routing.module.ts │ │ │ │ ├── code-mapping.module.ts │ │ │ │ ├── import-codes │ │ │ │ │ ├── column-mapping │ │ │ │ │ │ ├── column-mapping-filters │ │ │ │ │ │ │ ├── column-mapping-filters.component.html │ │ │ │ │ │ │ ├── column-mapping-filters.component.scss │ │ │ │ │ │ │ └── column-mapping-filters.component.ts │ │ │ │ │ │ ├── column-mapping-form │ │ │ │ │ │ │ ├── column-mapping-form.component.html │ │ │ │ │ │ │ ├── column-mapping-form.component.scss │ │ │ │ │ │ │ └── column-mapping-form.component.ts │ │ │ │ │ │ ├── column-mapping.component.html │ │ │ │ │ │ ├── column-mapping.component.scss │ │ │ │ │ │ ├── column-mapping.component.ts │ │ │ │ │ │ └── import-codes-grid │ │ │ │ │ │ │ ├── import-codes-grid.component.scss │ │ │ │ │ │ │ └── import-codes-grid.component.ts │ │ │ │ │ ├── import-codes.component.html │ │ │ │ │ ├── import-codes.component.scss │ │ │ │ │ ├── import-codes.component.ts │ │ │ │ │ ├── import-vocabulary │ │ │ │ │ │ ├── import-vocabulary-buttons │ │ │ │ │ │ │ ├── import-vocabulary-buttons.component.html │ │ │ │ │ │ │ ├── import-vocabulary-buttons.component.scss │ │ │ │ │ │ │ └── import-vocabulary-buttons.component.ts │ │ │ │ │ │ ├── import-vocabulary.component.html │ │ │ │ │ │ ├── import-vocabulary.component.scss │ │ │ │ │ │ ├── import-vocabulary.component.ts │ │ │ │ │ │ └── remove-vocabulary-confirm │ │ │ │ │ │ │ ├── remove-vocabulary-confirm.component.html │ │ │ │ │ │ │ ├── remove-vocabulary-confirm.component.scss │ │ │ │ │ │ │ └── remove-vocabulary-confirm.component.ts │ │ │ │ │ └── styles │ │ │ │ │ │ ├── column-mapping-panel.scss │ │ │ │ │ │ └── import-codes-wrapper.scss │ │ │ │ └── mapping-codes │ │ │ │ │ ├── edit-mapping-panel │ │ │ │ │ ├── edit-code-mapping-grid │ │ │ │ │ │ ├── edit-code-mapping-grid.component.html │ │ │ │ │ │ ├── edit-code-mapping-grid.component.scss │ │ │ │ │ │ └── edit-code-mapping-grid.component.ts │ │ │ │ │ ├── edit-mapping-panel.component.html │ │ │ │ │ ├── edit-mapping-panel.component.scss │ │ │ │ │ ├── edit-mapping-panel.component.ts │ │ │ │ │ └── edit-mapping-panel.ts │ │ │ │ │ ├── mapping-codes.component.html │ │ │ │ │ ├── mapping-codes.component.scss │ │ │ │ │ ├── mapping-codes.component.ts │ │ │ │ │ ├── match-score-grid │ │ │ │ │ ├── match-score-grid.columns.ts │ │ │ │ │ ├── match-score-grid.component.html │ │ │ │ │ ├── match-score-grid.component.scss │ │ │ │ │ ├── match-score-grid.component.ts │ │ │ │ │ └── match-score-grid.ts │ │ │ │ │ └── save-vocabulary-popup │ │ │ │ │ ├── confirm-overwrite-vocab │ │ │ │ │ ├── confirm-overwrite-vocab.component.html │ │ │ │ │ ├── confirm-overwrite-vocab.component.scss │ │ │ │ │ └── confirm-overwrite-vocab.component.ts │ │ │ │ │ ├── save-vocabulary-popup.component.html │ │ │ │ │ ├── save-vocabulary-popup.component.scss │ │ │ │ │ └── save-vocabulary-popup.component.ts │ │ │ ├── comfy │ │ │ │ ├── columns-list │ │ │ │ │ ├── column-info │ │ │ │ │ │ ├── column-info.component.html │ │ │ │ │ │ ├── column-info.component.scss │ │ │ │ │ │ └── column-info.component.ts │ │ │ │ │ ├── column-list.ts │ │ │ │ │ ├── columns-list.component.html │ │ │ │ │ ├── columns-list.component.scss │ │ │ │ │ └── columns-list.component.ts │ │ │ │ ├── comfy-routing.module.ts │ │ │ │ ├── comfy.component.html │ │ │ │ ├── comfy.component.scss │ │ │ │ ├── comfy.component.ts │ │ │ │ ├── comfy.module.ts │ │ │ │ └── highlight-table │ │ │ │ │ └── highlight-table.directive.ts │ │ │ ├── icons.ts │ │ │ └── mapping │ │ │ │ ├── concept-fileds-list.json │ │ │ │ ├── concept-transformation │ │ │ │ ├── concept-column │ │ │ │ │ ├── concept-column.component.html │ │ │ │ │ ├── concept-column.component.scss │ │ │ │ │ └── concept-column.component.ts │ │ │ │ ├── concept-transformation.component.html │ │ │ │ ├── concept-transformation.component.scss │ │ │ │ └── concept-transformation.component.ts │ │ │ │ ├── groups-conf.json │ │ │ │ ├── lookup │ │ │ │ ├── lookup.component.html │ │ │ │ ├── lookup.component.scss │ │ │ │ └── lookup.component.ts │ │ │ │ ├── mapping-routing.module.ts │ │ │ │ ├── mapping.component.html │ │ │ │ ├── mapping.component.scss │ │ │ │ ├── mapping.component.ts │ │ │ │ ├── mapping.module.ts │ │ │ │ ├── panel │ │ │ │ ├── area │ │ │ │ │ ├── area.component.html │ │ │ │ │ ├── area.component.scss │ │ │ │ │ └── area.component.ts │ │ │ │ ├── directives │ │ │ │ │ └── draggable.directive.ts │ │ │ │ ├── panel-table │ │ │ │ │ ├── panel-table.component.html │ │ │ │ │ ├── panel-table.component.scss │ │ │ │ │ ├── panel-table.component.ts │ │ │ │ │ └── similar-types.json │ │ │ │ ├── panel.component.html │ │ │ │ ├── panel.component.scss │ │ │ │ ├── panel.component.ts │ │ │ │ └── target-clone-dialog │ │ │ │ │ ├── target-clone-dialog.component.html │ │ │ │ │ ├── target-clone-dialog.component.scss │ │ │ │ │ └── target-clone-dialog.component.ts │ │ │ │ ├── similar-names-map.json │ │ │ │ ├── sql-transformation │ │ │ │ ├── manual-transformation │ │ │ │ │ ├── manual-transformation.component.html │ │ │ │ │ ├── manual-transformation.component.scss │ │ │ │ │ └── manual-transformation.component.ts │ │ │ │ ├── sql-transformation.component.html │ │ │ │ ├── sql-transformation.component.scss │ │ │ │ ├── sql-transformation.component.ts │ │ │ │ └── visual-transformation │ │ │ │ │ ├── function │ │ │ │ │ ├── date-add-transformation-function │ │ │ │ │ │ ├── date-add-transformation-function.component.html │ │ │ │ │ │ ├── date-add-transformation-function.component.scss │ │ │ │ │ │ ├── date-add-transformation-function.component.ts │ │ │ │ │ │ ├── date-add-transformation-function.spec.ts │ │ │ │ │ │ └── date-add-transformation-function.ts │ │ │ │ │ ├── date-part-transformation-function │ │ │ │ │ │ ├── date-part-transformation-function.component.html │ │ │ │ │ │ ├── date-part-transformation-function.component.scss │ │ │ │ │ │ ├── date-part-transformation-function.component.ts │ │ │ │ │ │ ├── date-part-transformation-function.spec.ts │ │ │ │ │ │ └── date-part-transformation-function.ts │ │ │ │ │ ├── no-args-transformation-function │ │ │ │ │ │ ├── function │ │ │ │ │ │ │ ├── lower-transformation-function.ts │ │ │ │ │ │ │ ├── trim-transformation-function.ts │ │ │ │ │ │ │ └── upper-transformation-function.ts │ │ │ │ │ │ ├── no-args-transformation-function.component.ts │ │ │ │ │ │ └── no-args-transformation-function.ts │ │ │ │ │ ├── replace-transformation-function │ │ │ │ │ │ ├── replace-transformation-function.component.html │ │ │ │ │ │ ├── replace-transformation-function.component.scss │ │ │ │ │ │ ├── replace-transformation-function.component.ts │ │ │ │ │ │ ├── replace-transformation-function.spec.ts │ │ │ │ │ │ └── replace-transformation-function.ts │ │ │ │ │ ├── switch-case-transformation-function │ │ │ │ │ │ ├── switch-case-transformation-function.component.html │ │ │ │ │ │ ├── switch-case-transformation-function.component.scss │ │ │ │ │ │ ├── switch-case-transformation-function.component.ts │ │ │ │ │ │ ├── switch-case-transformation-function.spec.ts │ │ │ │ │ │ └── switch-case-transformation-function.ts │ │ │ │ │ ├── transformation-function.component.ts │ │ │ │ │ ├── transformation-function.ts │ │ │ │ │ └── typed-transformation-function.ts │ │ │ │ │ ├── visual-transformation.component.html │ │ │ │ │ ├── visual-transformation.component.scss │ │ │ │ │ ├── visual-transformation.component.ts │ │ │ │ │ └── visual-transformation.ts │ │ │ │ └── transform-config │ │ │ │ ├── transform-config.component.html │ │ │ │ ├── transform-config.component.scss │ │ │ │ └── transform-config.component.ts │ │ ├── grid │ │ │ ├── auxiliary │ │ │ │ └── grid-column │ │ │ │ │ ├── grid-column.component.html │ │ │ │ │ ├── grid-column.component.scss │ │ │ │ │ └── grid-column.component.ts │ │ │ ├── grid.component.scss │ │ │ ├── grid.component.ts │ │ │ ├── grid.module.ts │ │ │ ├── navigation-grid │ │ │ │ ├── navigation-grid.component.html │ │ │ │ ├── navigation-grid.component.scss │ │ │ │ └── navigation-grid.component.ts │ │ │ └── selectable-grid │ │ │ │ ├── grid-checkbox │ │ │ │ ├── grid-checkbox.component.html │ │ │ │ ├── grid-checkbox.component.scss │ │ │ │ └── grid-checkbox.component.ts │ │ │ │ ├── selectable-grid.component.html │ │ │ │ ├── selectable-grid.component.scss │ │ │ │ └── selectable-grid.component.ts │ │ ├── guards │ │ │ ├── auth │ │ │ │ ├── already-logged-in.guard.ts │ │ │ │ ├── already-registered.guard.ts │ │ │ │ ├── auth.guard.ts │ │ │ │ ├── link-expired.guard.ts │ │ │ │ └── reset-password.guard.ts │ │ │ ├── code-mapping │ │ │ │ ├── import-codes.guard.ts │ │ │ │ └── mapping-codes.guard.ts │ │ │ └── mapping │ │ │ │ └── mapping.guard.ts │ │ ├── infrastructure │ │ │ ├── command.ts │ │ │ └── utility.ts │ │ ├── interceptors │ │ │ ├── azure-interceptor.service.ts │ │ │ ├── server-error.interceptor.ts │ │ │ ├── smtp-interceptor.service.ts │ │ │ └── username.interceptor.ts │ │ ├── material │ │ │ └── cdm-custom-material.module.ts │ │ ├── mockups │ │ │ └── schema.mockup.json │ │ ├── models │ │ │ ├── area.ts │ │ │ ├── arrow-cache.spec.ts │ │ │ ├── arrow-cache.ts │ │ │ ├── arrow.spec.ts │ │ │ ├── arrow.ts │ │ │ ├── auth │ │ │ │ └── user.ts │ │ │ ├── cdm-builder │ │ │ │ ├── cdm-builder-status.ts │ │ │ │ └── cdm-settings.ts │ │ │ ├── clones.ts │ │ │ ├── code-mapping │ │ │ │ ├── code-mapping-params.ts │ │ │ │ ├── code-mapping.ts │ │ │ │ ├── code.ts │ │ │ │ ├── concept.ts │ │ │ │ ├── console-header.ts │ │ │ │ ├── filters.ts │ │ │ │ ├── import-codes-state.ts │ │ │ │ ├── scored-concept-cache.ts │ │ │ │ ├── scored-concept.ts │ │ │ │ ├── search-by-term-params.ts │ │ │ │ ├── search-concept-filters.ts │ │ │ │ ├── search-mode.ts │ │ │ │ ├── source-code.ts │ │ │ │ └── target-concept.ts │ │ │ ├── comment.ts │ │ │ ├── connection.ts │ │ │ ├── connector.ts │ │ │ ├── const-event.ts │ │ │ ├── constant-cache.ts │ │ │ ├── conversion │ │ │ │ ├── conversion-status.ts │ │ │ │ └── conversion.ts │ │ │ ├── etl-configuration.ts │ │ │ ├── etl-mapping-for-zip-xml-generation.ts │ │ │ ├── filter │ │ │ │ └── filter.ts │ │ │ ├── filtered-fields.ts │ │ │ ├── grid │ │ │ │ ├── grid.ts │ │ │ │ ├── pagination.ts │ │ │ │ └── selectable.ts │ │ │ ├── perseus │ │ │ │ ├── column-info-response.ts │ │ │ │ ├── column-info.ts │ │ │ │ ├── concept-field.ts │ │ │ │ ├── concept-lookup.ts │ │ │ │ ├── concept-tables.ts │ │ │ │ ├── concept.ts │ │ │ │ ├── concepts.ts │ │ │ │ ├── etl-mapping.ts │ │ │ │ ├── generate-etl-archive-request.ts │ │ │ │ ├── lookup-list-item.ts │ │ │ │ ├── lookup-request.ts │ │ │ │ ├── lookup-type.ts │ │ │ │ ├── lookup.ts │ │ │ │ ├── scan-report-request.ts │ │ │ │ ├── table-info-response.ts │ │ │ │ ├── upload-etl-mapping-response.ts │ │ │ │ ├── upload-scan-report-response.ts │ │ │ │ └── view-sql-response.ts │ │ │ ├── popup │ │ │ │ └── save-model.ts │ │ │ ├── progress-console │ │ │ │ ├── progress-log-status.ts │ │ │ │ └── progress-log.ts │ │ │ ├── reset-warning-data.ts │ │ │ ├── row.spec.ts │ │ │ ├── row.ts │ │ │ ├── scan-data │ │ │ │ ├── progress-notification.ts │ │ │ │ ├── scan-result.ts │ │ │ │ └── state.ts │ │ │ ├── sql-functions-injector.ts │ │ │ ├── state.ts │ │ │ ├── table.ts │ │ │ ├── target-config.ts │ │ │ ├── transformation-dialog-data.ts │ │ │ ├── transformation-dialog-result.ts │ │ │ ├── transformation-input │ │ │ │ └── sql-string-functions.ts │ │ │ ├── transformation │ │ │ │ ├── datepart.ts │ │ │ │ ├── function-type.ts │ │ │ │ ├── sql-for-transformation.ts │ │ │ │ ├── sql-function-for-transformation.ts │ │ │ │ ├── sql-transform-mode.ts │ │ │ │ └── transformation-function-type.ts │ │ │ ├── vocabulary-search │ │ │ │ ├── concept.ts │ │ │ │ ├── vocabulary-search-state.ts │ │ │ │ └── vocabulray-search.ts │ │ │ └── white-rabbit │ │ │ │ ├── connection-result.ts │ │ │ │ ├── data-type-group.ts │ │ │ │ ├── db-settings.ts │ │ │ │ ├── fake-data-request.ts │ │ │ │ ├── fake-data-settings.ts │ │ │ │ ├── files-settings.ts │ │ │ │ ├── scan-data-params.ts │ │ │ │ ├── scan-data-state.ts │ │ │ │ ├── scan-settings-type.ts │ │ │ │ ├── scan-settings.ts │ │ │ │ └── table-to-scan.ts │ │ ├── popups │ │ │ ├── add-constant-popup │ │ │ │ ├── add-constant-popup.component.html │ │ │ │ ├── add-constant-popup.component.scss │ │ │ │ └── add-constant-popup.component.ts │ │ │ ├── cdm-filter │ │ │ │ ├── CdmByTypes.json │ │ │ │ ├── cdm-filter.component.html │ │ │ │ ├── cdm-filter.component.scss │ │ │ │ └── cdm-filter.component.ts │ │ │ ├── cdm-version-dialog │ │ │ │ ├── cdm-version-dialog.component.html │ │ │ │ ├── cdm-version-dialog.component.scss │ │ │ │ └── cdm-version-dialog.component.ts │ │ │ ├── choose-transformation-type-popup │ │ │ │ ├── choose-transformation-type-popup.component.html │ │ │ │ ├── choose-transformation-type-popup.component.scss │ │ │ │ └── choose-transformation-type-popup.component.ts │ │ │ ├── comment-popup │ │ │ │ ├── comment-popup.component.html │ │ │ │ ├── comment-popup.component.scss │ │ │ │ └── comment-popup.component.ts │ │ │ ├── delete-warning │ │ │ │ ├── delete-warning.component.html │ │ │ │ ├── delete-warning.component.scss │ │ │ │ └── delete-warning.component.ts │ │ │ ├── error-popup │ │ │ │ ├── error-popup.component.html │ │ │ │ ├── error-popup.component.scss │ │ │ │ └── error-popup.component.ts │ │ │ ├── help-popup │ │ │ │ ├── help-popup.component.html │ │ │ │ ├── help-popup.component.scss │ │ │ │ └── help-popup.component.ts │ │ │ ├── logout │ │ │ │ ├── logout.component.html │ │ │ │ ├── logout.component.scss │ │ │ │ └── logout.component.ts │ │ │ ├── on-boarding │ │ │ │ ├── on-boarding.component.html │ │ │ │ ├── on-boarding.component.scss │ │ │ │ ├── on-boarding.component.ts │ │ │ │ └── on-boarding.meta.ts │ │ │ ├── open-save-dialog │ │ │ │ ├── open-save-dialog.component.html │ │ │ │ ├── open-save-dialog.component.scss │ │ │ │ └── open-save-dialog.component.ts │ │ │ ├── popups.module.ts │ │ │ ├── preview-popup │ │ │ │ ├── preview-popup.component.html │ │ │ │ ├── preview-popup.component.scss │ │ │ │ ├── preview-popup.component.ts │ │ │ │ └── prism.component.ts │ │ │ ├── reset-warning │ │ │ │ ├── reset-warning.component.html │ │ │ │ ├── reset-warning.component.scss │ │ │ │ └── reset-warning.component.ts │ │ │ ├── save-mapping-dialog │ │ │ │ ├── save-mapping-dialog.component.html │ │ │ │ ├── save-mapping-dialog.component.scss │ │ │ │ └── save-mapping-dialog.component.ts │ │ │ ├── select-concept-field │ │ │ │ ├── select-concept-field.component.html │ │ │ │ ├── select-concept-field.component.scss │ │ │ │ └── select-concept-field.component.ts │ │ │ ├── select-table-dropdown │ │ │ │ ├── select-table-dropdown.component.html │ │ │ │ ├── select-table-dropdown.component.scss │ │ │ │ └── select-table-dropdown.component.ts │ │ │ ├── transformation-type │ │ │ │ ├── transformation-type.component.html │ │ │ │ ├── transformation-type.component.scss │ │ │ │ └── transformation-type.component.ts │ │ │ └── warning-popup │ │ │ │ ├── warning-popup.component.html │ │ │ │ ├── warning-popup.component.scss │ │ │ │ └── warning-popup.component.ts │ │ ├── scan-data │ │ │ ├── auxiliary │ │ │ │ ├── connection-error-popup │ │ │ │ │ ├── connection-error-popup.component.html │ │ │ │ │ ├── connection-error-popup.component.scss │ │ │ │ │ └── connection-error-popup.component.ts │ │ │ │ ├── data-base-exist-warning-popup │ │ │ │ │ ├── data-base-exist-warning-popup.component.html │ │ │ │ │ ├── data-base-exist-warning-popup.component.scss │ │ │ │ │ └── data-base-exist-warning-popup.component.ts │ │ │ │ ├── progress-console-wrapper │ │ │ │ │ ├── console-wrapper.component.scss │ │ │ │ │ └── progress-console-wrapper.component.ts │ │ │ │ ├── progress-console │ │ │ │ │ ├── progress-console.component.html │ │ │ │ │ ├── progress-console.component.scss │ │ │ │ │ └── progress-console.component.ts │ │ │ │ ├── resource-form │ │ │ │ │ └── abstract-resource-form.component.ts │ │ │ │ └── test-connection │ │ │ │ │ ├── test-connection.component.html │ │ │ │ │ ├── test-connection.component.scss │ │ │ │ │ └── test-connection.component.ts │ │ │ ├── cdm-dialog │ │ │ │ ├── cdm-console-wrapper │ │ │ │ │ ├── cdm-console-wrapper.component.html │ │ │ │ │ ├── cdm-console-wrapper.component.scss │ │ │ │ │ └── cdm-console-wrapper.component.ts │ │ │ │ ├── cdm-dialog.component.html │ │ │ │ ├── cdm-dialog.component.scss │ │ │ │ ├── cdm-dialog.component.ts │ │ │ │ ├── cdm-form │ │ │ │ │ ├── cdm-connect-form │ │ │ │ │ │ ├── cdm-connect-form.component.html │ │ │ │ │ │ └── cdm-connect-form.component.ts │ │ │ │ │ ├── cdm-destination-form │ │ │ │ │ │ ├── cdm-destination-form.component.html │ │ │ │ │ │ ├── cdm-destination-form.component.scss │ │ │ │ │ │ └── cdm-destination-form.component.ts │ │ │ │ │ ├── cdm-fake-data-form │ │ │ │ │ │ ├── cdm-fake-data-form.component.html │ │ │ │ │ │ ├── cdm-fake-data-form.component.scss │ │ │ │ │ │ └── cdm-fake-data-form.component.ts │ │ │ │ │ ├── cdm-form.component.html │ │ │ │ │ ├── cdm-form.component.scss │ │ │ │ │ ├── cdm-form.component.ts │ │ │ │ │ └── cdm-source-form │ │ │ │ │ │ ├── cdm-source-form.component.html │ │ │ │ │ │ ├── cdm-source-form.component.scss │ │ │ │ │ │ └── cdm-source-form.component.ts │ │ │ │ └── cdm-tables-settings │ │ │ │ │ ├── cdm-tables-settings.component.html │ │ │ │ │ ├── cdm-tables-settings.component.scss │ │ │ │ │ └── cdm-tables-settings.component.ts │ │ │ ├── code-mapping-dialog │ │ │ │ ├── code-mapping-console-wrapper │ │ │ │ │ ├── code-mapping-console-wrapper.component.html │ │ │ │ │ ├── code-mapping-console-wrapper.component.scss │ │ │ │ │ └── code-mapping-console-wrapper.component.ts │ │ │ │ ├── code-mapping-dialog.component.html │ │ │ │ ├── code-mapping-dialog.component.scss │ │ │ │ └── code-mapping-dialog.component.ts │ │ │ ├── conversion-dialog-status.ts │ │ │ ├── conversion-dialog.ts │ │ │ ├── dqd-dialog │ │ │ │ ├── dqd-console-wrapper │ │ │ │ │ ├── dqd-console-wrapper.component.html │ │ │ │ │ ├── dqd-console-wrapper.component.scss │ │ │ │ │ └── dqd-console-wrapper.component.ts │ │ │ │ ├── dqd-dialog.component.html │ │ │ │ ├── dqd-dialog.component.scss │ │ │ │ ├── dqd-dialog.component.ts │ │ │ │ └── dqd-form │ │ │ │ │ ├── dqd-form.component.html │ │ │ │ │ ├── dqd-form.component.scss │ │ │ │ │ └── dqd-form.component.ts │ │ │ ├── fake-data-dialog │ │ │ │ ├── fake-console-wrapper │ │ │ │ │ ├── fake-console-wrapper.component.html │ │ │ │ │ ├── fake-console-wrapper.component.scss │ │ │ │ │ └── fake-console-wrapper.component.ts │ │ │ │ ├── fake-data-dialog.component.html │ │ │ │ ├── fake-data-dialog.component.scss │ │ │ │ ├── fake-data-dialog.component.ts │ │ │ │ └── fake-data-form │ │ │ │ │ ├── fake-data-form.component.html │ │ │ │ │ ├── fake-data-form.component.scss │ │ │ │ │ └── fake-data-form.component.ts │ │ │ ├── scan-data-dialog │ │ │ │ ├── scan-console-wrapper │ │ │ │ │ ├── scan-console-wrapper.component.html │ │ │ │ │ ├── scan-console-wrapper.component.scss │ │ │ │ │ └── scan-console-wrapper.component.ts │ │ │ │ ├── scan-data-dialog.component.html │ │ │ │ ├── scan-data-dialog.component.scss │ │ │ │ ├── scan-data-dialog.component.ts │ │ │ │ └── scan-data-form │ │ │ │ │ ├── connect-form │ │ │ │ │ ├── connect-form.component.html │ │ │ │ │ ├── connect-form.component.scss │ │ │ │ │ ├── connect-form.component.ts │ │ │ │ │ ├── db-settings-form │ │ │ │ │ │ ├── db-settings-form.component.html │ │ │ │ │ │ └── db-settings-form.component.ts │ │ │ │ │ └── file-settings-form │ │ │ │ │ │ ├── file-settings-form.component.html │ │ │ │ │ │ └── file-settings-form.component.ts │ │ │ │ │ ├── scan-data-form.component.html │ │ │ │ │ ├── scan-data-form.component.scss │ │ │ │ │ ├── scan-data-form.component.ts │ │ │ │ │ └── tables-to-scan │ │ │ │ │ ├── scan-params │ │ │ │ │ ├── scan-params.component.html │ │ │ │ │ ├── scan-params.component.scss │ │ │ │ │ └── scan-params.component.ts │ │ │ │ │ ├── table-to-scan │ │ │ │ │ ├── table-to-scan.component.html │ │ │ │ │ ├── table-to-scan.component.scss │ │ │ │ │ └── table-to-scan.component.ts │ │ │ │ │ ├── tables-to-scan.component.html │ │ │ │ │ ├── tables-to-scan.component.scss │ │ │ │ │ └── tables-to-scan.component.ts │ │ │ ├── scan-data.constants.ts │ │ │ ├── scan-data.module.ts │ │ │ └── styles │ │ │ │ ├── _variables.scss │ │ │ │ ├── file-input.scss │ │ │ │ ├── scan-data-buttons.scss │ │ │ │ ├── scan-data-connect-form.scss │ │ │ │ ├── scan-data-form.scss │ │ │ │ ├── scan-data-normalize.scss │ │ │ │ ├── scan-data-popup.scss │ │ │ │ ├── scan-data-step.scss │ │ │ │ └── scan-dialog.scss │ │ ├── server-error │ │ │ ├── server-error-icon │ │ │ │ ├── server-error-icon.component.html │ │ │ │ ├── server-error-icon.component.scss │ │ │ │ └── server-error-icon.component.ts │ │ │ ├── server-error-popup │ │ │ │ ├── server-error-popup.component.html │ │ │ │ └── server-error-popup.component.ts │ │ │ ├── server-error.component.scss │ │ │ ├── server-error.component.ts │ │ │ ├── server-error.module.ts │ │ │ └── server-not-responding-popup │ │ │ │ ├── server-not-responding-popup.component.html │ │ │ │ └── server-not-responding-popup.component.ts │ │ ├── services │ │ │ ├── app-connector.service.ts │ │ │ ├── athena │ │ │ │ ├── vocabulary-observer.service.ts │ │ │ │ ├── vocabulary-search-state.service.ts │ │ │ │ └── vocabulary-search.service.ts │ │ │ ├── auth │ │ │ │ ├── auth-injector.ts │ │ │ │ ├── auth-state.service.ts │ │ │ │ ├── auth.service.ts │ │ │ │ ├── azure-auth.service.ts │ │ │ │ ├── fake-auth.service.ts │ │ │ │ └── smtp-auth.service.ts │ │ │ ├── breadcrumb │ │ │ │ ├── breadcrumb.service.ts │ │ │ │ ├── can-redirect-mapping-codes.service.ts │ │ │ │ ├── can-redirect-mapping.service.ts │ │ │ │ └── can-redirect.service.ts │ │ │ ├── bridge.service.ts │ │ │ ├── cdm-builder │ │ │ │ ├── cdm-builder.service.ts │ │ │ │ ├── cdm-buttons-state.service.ts │ │ │ │ └── cdm-state.service.ts │ │ │ ├── comment.service.ts │ │ │ ├── common-utils.service.ts │ │ │ ├── common.service.ts │ │ │ ├── concept-transformation.sevice.ts │ │ │ ├── data-quality-check │ │ │ │ ├── data-quality-check-state.service.ts │ │ │ │ └── data-quality-check.service.ts │ │ │ ├── data.service.ts │ │ │ ├── draw.service.ts │ │ │ ├── etl-configuration.service.ts │ │ │ ├── overlay │ │ │ │ ├── overlay-config-options.interface.ts │ │ │ │ ├── overlay-dialog-data.ts │ │ │ │ ├── overlay.service.ts │ │ │ │ └── positions.json │ │ │ ├── perseus │ │ │ │ ├── field-type.service.ts │ │ │ │ ├── perseus-api.service.ts │ │ │ │ ├── perseus-lookup.service.ts │ │ │ │ ├── perseus-xml.service.ts │ │ │ │ └── user-schema.service.ts │ │ │ ├── report │ │ │ │ ├── comments-for-report.ts │ │ │ │ ├── image │ │ │ │ │ ├── canvas-wrapper.ts │ │ │ │ │ ├── draw-image-util.spec.ts │ │ │ │ │ ├── draw-image-util.ts │ │ │ │ │ └── mapping-image.ts │ │ │ │ ├── logic-for-report.ts │ │ │ │ ├── report-creator.ts │ │ │ │ ├── report-generation.service.ts │ │ │ │ ├── sql-keywords.ts │ │ │ │ ├── word-report-creator.spec.ts │ │ │ │ └── word-report-creator.ts │ │ │ ├── state │ │ │ │ ├── auth-facade.service.ts │ │ │ │ ├── reset-state.service.ts │ │ │ │ └── state.service.ts │ │ │ ├── store.service.ts │ │ │ ├── upload.service.ts │ │ │ ├── usagi │ │ │ │ ├── import-codes.service.ts │ │ │ │ ├── import-vocabularies.service.ts │ │ │ │ └── scored-concepts-cache.service.ts │ │ │ ├── validation.service.spec.ts │ │ │ ├── validation.service.ts │ │ │ ├── vocabularies.service.ts │ │ │ ├── white-rabbit │ │ │ │ ├── fake-data-state.service.ts │ │ │ │ ├── fake-data.service.ts │ │ │ │ ├── scan-data-state.service.ts │ │ │ │ ├── scan-data-upload.service.ts │ │ │ │ └── scan-data.service.ts │ │ │ └── zip-xml-mapping-model-service.ts │ │ ├── shared │ │ │ ├── base │ │ │ │ └── base.component.ts │ │ │ ├── cdm-checkbox │ │ │ │ ├── cdm-checkbox.component.html │ │ │ │ ├── cdm-checkbox.component.scss │ │ │ │ └── cdm-checkbox.component.ts │ │ │ ├── close-dialog-button │ │ │ │ ├── close-dialog-button.component.scss │ │ │ │ └── close-dialog-button.component.ts │ │ │ ├── filters │ │ │ │ ├── filter-color-point │ │ │ │ │ ├── filter-color-point.component.html │ │ │ │ │ ├── filter-color-point.component.scss │ │ │ │ │ └── filter-color-point.component.ts │ │ │ │ └── filter-dropdown │ │ │ │ │ ├── filter-dropdown-label │ │ │ │ │ ├── filter-dropdown-label.component.html │ │ │ │ │ ├── filter-dropdown-label.component.scss │ │ │ │ │ └── filter-dropdown-label.component.ts │ │ │ │ │ ├── filter-dropdown.component.html │ │ │ │ │ ├── filter-dropdown.component.scss │ │ │ │ │ ├── filter-dropdown.component.ts │ │ │ │ │ ├── filter-dropdown.ts │ │ │ │ │ └── filter-list │ │ │ │ │ ├── filter-list.component.html │ │ │ │ │ ├── filter-list.component.scss │ │ │ │ │ └── filter-list.component.ts │ │ │ ├── hint │ │ │ │ ├── hint-overlay │ │ │ │ │ ├── hint-overlay.component.html │ │ │ │ │ ├── hint-overlay.component.scss │ │ │ │ │ └── hint-overlay.component.ts │ │ │ │ ├── hint.component.html │ │ │ │ ├── hint.component.scss │ │ │ │ ├── hint.component.ts │ │ │ │ ├── hints.ts │ │ │ │ └── warning-hint │ │ │ │ │ ├── warning-hint.component.html │ │ │ │ │ ├── warning-hint.component.scss │ │ │ │ │ └── warning-hint.component.ts │ │ │ ├── person-mapping-warning-dialog │ │ │ │ ├── person-mapping-warning-dialog.component.html │ │ │ │ ├── person-mapping-warning-dialog.component.scss │ │ │ │ └── person-mapping-warning-dialog.component.ts │ │ │ ├── pipes │ │ │ │ ├── capitalize.pipe.ts │ │ │ │ ├── pretty-name.pipe.ts │ │ │ │ ├── split-capitalized.pipe.ts │ │ │ │ ├── type-to-icon.pipe.ts │ │ │ │ ├── typeof.pipe.ts │ │ │ │ └── xml-prettier.ts │ │ │ ├── popup │ │ │ │ ├── popup.component.ts │ │ │ │ ├── popup.styles.scss │ │ │ │ └── popup.template.html │ │ │ ├── search-by-name │ │ │ │ ├── search-by-name.component.html │ │ │ │ ├── search-by-name.component.scss │ │ │ │ └── search-by-name.component.ts │ │ │ ├── search-input │ │ │ │ ├── search-input.component.html │ │ │ │ ├── search-input.component.scss │ │ │ │ └── search-input.component.ts │ │ │ ├── set-delimiter-dialog │ │ │ │ ├── set-delimiter-dialog.component.html │ │ │ │ ├── set-delimiter-dialog.component.scss │ │ │ │ └── set-delimiter-dialog.component.ts │ │ │ ├── shared.module.ts │ │ │ ├── sql-editor │ │ │ │ ├── sql-editor.component.html │ │ │ │ ├── sql-editor.component.scss │ │ │ │ ├── sql-editor.component.ts │ │ │ │ ├── sql-editor.data.ts │ │ │ │ ├── sql-editor.spec.ts │ │ │ │ └── sql-editor.ts │ │ │ └── text-width │ │ │ │ └── text-width.directive.ts │ │ ├── styles │ │ │ ├── _mixins.scss │ │ │ ├── _variables.scss │ │ │ ├── codemirror.scss │ │ │ ├── material.scss │ │ │ ├── overlays.scss │ │ │ └── theme.scss │ │ ├── test │ │ │ ├── mock.ts │ │ │ ├── test-mapping.json │ │ │ └── test.consts.ts │ │ ├── toolbar │ │ │ ├── breadcrumb │ │ │ │ ├── breadcrumb.component.html │ │ │ │ ├── breadcrumb.component.scss │ │ │ │ └── breadcrump.component.ts │ │ │ ├── toolbar.component.html │ │ │ ├── toolbar.component.scss │ │ │ ├── toolbar.component.ts │ │ │ └── toolbar.module.ts │ │ ├── utils │ │ │ ├── arrow.ts │ │ │ ├── auth-util.ts │ │ │ ├── base64-util.ts │ │ │ ├── blob-util.ts │ │ │ ├── bridge.ts │ │ │ ├── cdm-adapter.ts │ │ │ ├── code-mapping-util.ts │ │ │ ├── code-mirror.ts │ │ │ ├── concept-util.ts │ │ │ ├── connector.ts │ │ │ ├── constant.ts │ │ │ ├── draw-utilites.ts │ │ │ ├── error.ts │ │ │ ├── etl-configuration-util.spec.ts │ │ │ ├── etl-configuration-util.ts │ │ │ ├── field-type.ts │ │ │ ├── file.spec.ts │ │ │ ├── file.ts │ │ │ ├── form.ts │ │ │ ├── html-utilities.ts │ │ │ ├── http-headers.ts │ │ │ ├── loading.ts │ │ │ ├── local.ts │ │ │ ├── lookup-util.ts │ │ │ ├── mapping-util.ts │ │ │ ├── math.ts │ │ │ ├── scan-data-util.ts │ │ │ ├── sort.ts │ │ │ ├── text-util.ts │ │ │ ├── text-utility.ts │ │ │ ├── text-width.ts │ │ │ └── transformtaion-dialog-util.ts │ │ └── vocabulary-search │ │ │ ├── chip │ │ │ ├── chip.component.html │ │ │ ├── chip.component.scss │ │ │ └── chip.component.ts │ │ │ ├── vocabulary-button │ │ │ ├── vocabulary-button.component.html │ │ │ ├── vocabulary-button.component.scss │ │ │ └── vocabulary-button.component.ts │ │ │ ├── vocabulary-search.component.html │ │ │ ├── vocabulary-search.component.scss │ │ │ ├── vocabulary-search.component.ts │ │ │ └── vocabulary-search.module.ts │ ├── assets │ │ ├── .gitkeep │ │ ├── env.js │ │ ├── env.template.js │ │ ├── icons │ │ │ ├── CDM_version.svg │ │ │ ├── code_mapping.svg │ │ │ ├── convert_data.svg │ │ │ ├── delete.svg │ │ │ ├── edit.svg │ │ │ ├── error.svg │ │ │ ├── filter.svg │ │ │ ├── folder.svg │ │ │ ├── folder_2.svg │ │ │ ├── generate_and_save.svg │ │ │ ├── generate_fake.svg │ │ │ ├── generate_html.svg │ │ │ ├── generate_md.svg │ │ │ ├── generate_report.svg │ │ │ ├── generate_word.svg │ │ │ ├── help.svg │ │ │ ├── hint.svg │ │ │ ├── logo_grey.svg │ │ │ ├── logo_white.svg │ │ │ ├── logout.svg │ │ │ ├── mapping.svg │ │ │ ├── new_mapping.svg │ │ │ ├── quality_check.svg │ │ │ ├── reset.svg │ │ │ ├── save.svg │ │ │ ├── scan_data.svg │ │ │ ├── search.svg │ │ │ ├── settings.svg │ │ │ ├── three_dot_menu.svg │ │ │ ├── vocabulary.svg │ │ │ └── warning.svg │ │ ├── txt │ │ │ ├── source_to_source │ │ │ │ ├── cvx.txt │ │ │ │ ├── icd10.txt │ │ │ │ ├── icd10cm.txt │ │ │ │ ├── icd9cm.txt │ │ │ │ ├── icd9proc.txt │ │ │ │ ├── loinc.txt │ │ │ │ ├── ndc.txt │ │ │ │ ├── nucc.txt │ │ │ │ ├── procedure.txt │ │ │ │ ├── read.txt │ │ │ │ ├── revenue.txt │ │ │ │ └── snomed.txt │ │ │ ├── source_to_standard │ │ │ │ ├── cms.txt │ │ │ │ ├── cpt4_modifier.txt │ │ │ │ ├── cvx.txt │ │ │ │ ├── icd10.txt │ │ │ │ ├── icd10cm.txt │ │ │ │ ├── icd9cm.txt │ │ │ │ ├── icd9proc.txt │ │ │ │ ├── loinc.txt │ │ │ │ ├── ndc.txt │ │ │ │ ├── nucc.txt │ │ │ │ ├── procedure.txt │ │ │ │ ├── read.txt │ │ │ │ ├── revenue.txt │ │ │ │ ├── snomed.txt │ │ │ │ └── ucum.txt │ │ │ ├── template_source_to_source.txt │ │ │ └── template_source_to_standard.txt │ │ └── vocabularies │ │ │ ├── conceptlist.json │ │ │ ├── domainlist.json │ │ │ └── lookuplist.json │ ├── environments │ │ ├── auth-strategies.ts │ │ ├── concept-tables.ts │ │ ├── environment.azure.ts │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── favicon.ico │ │ ├── mstile-150x150.png │ │ └── site.webmanifest │ ├── img │ │ └── logo.png │ ├── index.html │ ├── karma.conf.ci.js │ ├── karma.conf.js │ ├── main.ts │ ├── polyfills.ts │ ├── styles.scss │ ├── test.ts │ ├── tsconfig.app.json │ └── tsconfig.spec.json ├── sshd_config ├── tsconfig.base.json ├── tsconfig.json └── tslint.json ├── athena-api ├── .gitignore ├── Dockerfile ├── app.py ├── app_config.py ├── athena_api.py ├── config.py ├── entrypoint.sh ├── log.py ├── main.py ├── requirements.txt ├── service │ ├── search_service.py │ └── solr_core_service.py ├── sshd_config └── utils │ ├── constants.py │ ├── info_response.py │ ├── key_vaults.py │ └── search_util.py ├── auth ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── Dockerfile ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── softwarecountry │ │ │ └── perseus │ │ │ └── auth │ │ │ ├── AuthApplication.java │ │ │ ├── config │ │ │ └── AadOAuth2ResourceServerSecurityConfig.java │ │ │ ├── model │ │ │ ├── AppInfoResponse.java │ │ │ └── User.java │ │ │ ├── service │ │ │ ├── UserService.java │ │ │ └── UserServiceImpl.java │ │ │ ├── util │ │ │ ├── EmailUtil.java │ │ │ └── TokenAttributes.java │ │ │ └── web │ │ │ └── controller │ │ │ ├── AppInfoController.java │ │ │ ├── AuthController.java │ │ │ └── UserController.java │ └── resources │ │ ├── application-azure.yml │ │ ├── application.yml │ │ └── banner.txt │ └── test │ └── java │ └── com │ └── softwarecountry │ └── perseus │ └── auth │ ├── AuthApplicationTests.java │ ├── service │ └── UserServiceImplTest.java │ └── util │ └── EmailUtilTest.java ├── docker-compose.yaml ├── files-manager ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── Dockerfile ├── entrypoint.sh ├── mvnw ├── mvnw.cmd ├── pom.xml ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── arcadia │ │ │ │ └── perseus │ │ │ │ └── filesmanager │ │ │ │ ├── FilesManagerApplication.java │ │ │ │ ├── model │ │ │ │ ├── BlobData.java │ │ │ │ └── UserData.java │ │ │ │ ├── repository │ │ │ │ ├── BlobDataRepository.java │ │ │ │ └── UserDataRepository.java │ │ │ │ ├── service │ │ │ │ ├── DataService.java │ │ │ │ ├── DbDataService.java │ │ │ │ ├── HashService.java │ │ │ │ └── MD5Service.java │ │ │ │ └── web │ │ │ │ └── controller │ │ │ │ ├── DataController.java │ │ │ │ ├── InfoController.java │ │ │ │ └── response │ │ │ │ └── InfoResponse.java │ │ └── resources │ │ │ ├── application-azure.yml │ │ │ ├── application-docker.yml │ │ │ ├── application.yml │ │ │ └── banner.txt │ └── test │ │ ├── java │ │ └── com │ │ │ └── arcadia │ │ │ └── perseus │ │ │ └── filesmanager │ │ │ ├── FilesManagerApplicationTests.java │ │ │ ├── service │ │ │ ├── DbDataServiceTest.java │ │ │ └── MD5ServiceTest.java │ │ │ └── web │ │ │ └── controller │ │ │ └── DataControllerTest.java │ │ └── resources │ │ ├── application.yml │ │ ├── cprd_1k.etl │ │ └── mdcd_native_test.etl └── sshd_config ├── images ├── DQD.gif ├── FakeData.gif ├── LinkFieldsClone.gif ├── LinkFieldsConcept.gif ├── LinkFieldsCondition.gif ├── LinkFieldsConst.gif ├── LinkFieldsDirect.gif ├── LinkFieldsGroups.gif ├── LinkFieldsLookup.gif ├── LinkFieldsLookup2.gif ├── LinkFieldsMix.gif ├── LinkFieldsSimilar.gif ├── LinkFieldsSql.gif ├── LinkFieldsSqlManual.gif ├── LinkFieldsSqlVisual.gif ├── LinkFieldsStart.gif ├── LinkTables.gif ├── LinkTablesDrop.gif ├── LinkTablesOrderFilter.gif ├── LinkTablesSourceFields.gif ├── LinkTablesView.gif ├── OpenReport.gif ├── SaveOpen.gif ├── ScanData.gif ├── ScanSettings.PNG ├── Vocabulary.gif ├── concept.PNG ├── concept1.PNG ├── convertToCdm.gif ├── etldoc.gif ├── link_fields.PNG ├── link_tables.PNG ├── link_tables2.PNG ├── lookup.PNG ├── lookup1.PNG ├── start.PNG ├── start1.PNG ├── usagi.PNG ├── usagi.gif ├── usagi1.PNG ├── usagi2.gif ├── usagi3.gif ├── usagi4.gif ├── usagi5.gif └── usagi6.gif ├── nginx ├── Dockerfile ├── default.conf.template ├── docker-entrypoint.sh ├── server.azure-demo.conf ├── server.azure-dev.conf ├── server.azure-prod.conf ├── server.azure-test.conf ├── server.docker.conf ├── server.init.conf └── sshd_config ├── perseus-api ├── .gitignore ├── Dockerfile ├── app.py ├── app_config.py ├── config.py ├── create_tables.py ├── db.py ├── entrypoint.sh ├── flow.md ├── log.py ├── main.py ├── model │ ├── Batch.sql │ ├── __init__.py │ ├── base_model.py │ ├── etl_mapping.py │ ├── lookups │ │ ├── source_to_source │ │ │ ├── cvx.txt │ │ │ ├── icd10.txt │ │ │ ├── icd10cm.txt │ │ │ ├── icd9cm.txt │ │ │ ├── icd9proc.txt │ │ │ ├── loinc.txt │ │ │ ├── ndc.txt │ │ │ ├── nucc.txt │ │ │ ├── procedure.txt │ │ │ ├── read.txt │ │ │ ├── revenue.txt │ │ │ └── snomed.txt │ │ ├── source_to_standard │ │ │ ├── cms.txt │ │ │ ├── cpt4_modifier.txt │ │ │ ├── cvx.txt │ │ │ ├── icd10.txt │ │ │ ├── icd10cm.txt │ │ │ ├── icd9cm.txt │ │ │ ├── icd9proc.txt │ │ │ ├── loinc.txt │ │ │ ├── ndc.txt │ │ │ ├── nucc.txt │ │ │ ├── procedure.txt │ │ │ ├── read.txt │ │ │ ├── revenue.txt │ │ │ ├── snomed.txt │ │ │ └── ucum.txt │ │ ├── template_result.txt │ │ ├── template_result_only_source_to_standard.txt │ │ ├── template_source_to_source.txt │ │ └── template_source_to_standard.txt │ ├── sources │ │ ├── CDM │ │ │ ├── CDMv4.csv │ │ │ ├── CDMv5.0.1.csv │ │ │ ├── CDMv5.1.0.csv │ │ │ ├── CDMv5.2.0.csv │ │ │ ├── CDMv5.3.0.csv │ │ │ ├── CDMv5.3.1.csv │ │ │ ├── CDMv5.4.csv │ │ │ ├── CDMv5.csv │ │ │ └── CDMv6.csv │ │ ├── SQL │ │ ├── VOCABULARY.csv │ │ └── mock_input │ │ │ ├── DRUG_CLAIMS.json │ │ │ ├── ENROLLMENT_DETAIL.json │ │ │ ├── FACILITY_HEADER.json │ │ │ ├── HEALTH_RISK_ASSESSMENT.json │ │ │ ├── INPATIENT_ADMISSIONS.json │ │ │ ├── INPATIENT_SERVICES.json │ │ │ ├── LAB.json │ │ │ ├── LONG_TERM_CARE.json │ │ │ ├── L_LOCATION.json │ │ │ ├── L_PROVIDER.json │ │ │ ├── OUTPATIENT_SERVICES.json │ │ │ └── mock.json │ └── user_defined_lookup.py ├── perseus_api.py ├── requirements.txt ├── services │ ├── __init__.py │ ├── cache_service.py │ ├── cdm_schema.py │ ├── clear_cache_job.py │ ├── etl_archive_service.py │ ├── etl_mapping_service.py │ ├── files_manager_service.py │ ├── lookup_service.py │ ├── model │ │ ├── etl_archive_content.py │ │ └── scan_report_cache_info.py │ ├── request │ │ ├── generate_etl_archive_request.py │ │ ├── lookup_request.py │ │ ├── scan_report_request.py │ │ └── set_cdm_version_request.py │ ├── response │ │ ├── etl_mapping_response.py │ │ ├── file_save_reponse.py │ │ ├── lookup_list_item_response.py │ │ ├── upload_etl_archive_response.py │ │ └── upload_scan_report_response.py │ ├── scan_reports_service.py │ ├── source_schema_service.py │ └── xml_writer.py ├── sshd_config ├── test │ ├── delete_all_tables_in_scheme.py │ ├── resource │ │ ├── mdcd_native_test.xlsx │ │ └── test.etl │ ├── services │ │ ├── etl_archive_service_test.py │ │ └── files_manager_service_test.py │ └── utils │ │ ├── directory_util_test.py │ │ └── view_sql_util_test.py ├── utils │ ├── __init__.py │ ├── cdm_tables_settings.py │ ├── column_types_mapping.py │ ├── constants.py │ ├── directory_util.py │ ├── exceptions.py │ ├── file_util.py │ ├── info_response.py │ ├── key_vaults.py │ ├── similar_names_map.py │ ├── sql_util.py │ ├── string_util.py │ ├── username_header.py │ └── view_sql_util.py └── view │ ├── Table.py │ └── __init__.py ├── shared-db ├── Dockerfile └── init.sql ├── solr ├── Dockerfile ├── athena │ └── conf │ │ ├── db-data-config.xml │ │ ├── lang │ │ ├── contractions_ca.txt │ │ ├── contractions_fr.txt │ │ ├── contractions_ga.txt │ │ ├── contractions_it.txt │ │ ├── hyphenations_ga.txt │ │ ├── stemdict_nl.txt │ │ ├── stoptags_ja.txt │ │ ├── stopwords_ar.txt │ │ ├── stopwords_bg.txt │ │ ├── stopwords_ca.txt │ │ ├── stopwords_cz.txt │ │ ├── stopwords_da.txt │ │ ├── stopwords_de.txt │ │ ├── stopwords_el.txt │ │ ├── stopwords_en.txt │ │ ├── stopwords_es.txt │ │ ├── stopwords_et.txt │ │ ├── stopwords_eu.txt │ │ ├── stopwords_fa.txt │ │ ├── stopwords_fi.txt │ │ ├── stopwords_fr.txt │ │ ├── stopwords_ga.txt │ │ ├── stopwords_gl.txt │ │ ├── stopwords_hi.txt │ │ ├── stopwords_hu.txt │ │ ├── stopwords_hy.txt │ │ ├── stopwords_id.txt │ │ ├── stopwords_it.txt │ │ ├── stopwords_ja.txt │ │ ├── stopwords_lv.txt │ │ ├── stopwords_nl.txt │ │ ├── stopwords_no.txt │ │ ├── stopwords_pt.txt │ │ ├── stopwords_ro.txt │ │ ├── stopwords_ru.txt │ │ ├── stopwords_sv.txt │ │ ├── stopwords_th.txt │ │ ├── stopwords_tr.txt │ │ └── userdict_ja.txt │ │ ├── managed-schema │ │ ├── protwords.txt │ │ ├── solrconfig.xml │ │ ├── stopwords.txt │ │ └── synonyms.txt ├── entrypoint.sh ├── postgresql-42.2.19.jar ├── solr-index.sh ├── sshd_config └── usagi │ └── conf │ ├── db-data-config.xml │ ├── lang │ ├── contractions_ca.txt │ ├── contractions_fr.txt │ ├── contractions_ga.txt │ ├── contractions_it.txt │ ├── hyphenations_ga.txt │ ├── stemdict_nl.txt │ ├── stoptags_ja.txt │ ├── stopwords_ar.txt │ ├── stopwords_bg.txt │ ├── stopwords_ca.txt │ ├── stopwords_cz.txt │ ├── stopwords_da.txt │ ├── stopwords_de.txt │ ├── stopwords_el.txt │ ├── stopwords_en.txt │ ├── stopwords_es.txt │ ├── stopwords_et.txt │ ├── stopwords_eu.txt │ ├── stopwords_fa.txt │ ├── stopwords_fi.txt │ ├── stopwords_fr.txt │ ├── stopwords_ga.txt │ ├── stopwords_gl.txt │ ├── stopwords_hi.txt │ ├── stopwords_hu.txt │ ├── stopwords_hy.txt │ ├── stopwords_id.txt │ ├── stopwords_it.txt │ ├── stopwords_ja.txt │ ├── stopwords_lv.txt │ ├── stopwords_nl.txt │ ├── stopwords_no.txt │ ├── stopwords_pt.txt │ ├── stopwords_ro.txt │ ├── stopwords_ru.txt │ ├── stopwords_sv.txt │ ├── stopwords_th.txt │ ├── stopwords_tr.txt │ └── userdict_ja.txt │ ├── managed-schema │ ├── protwords.txt │ ├── solrconfig.xml │ ├── stopwords.txt │ └── synonyms.txt ├── startup.cmd ├── startup.sh ├── swagger-ui ├── Dockerfile ├── cdm-builder.yml ├── data-quality-dashboard.yml └── white-rabbit.yml ├── usagi-api ├── .gitignore ├── Dockerfile ├── app.py ├── app_config.py ├── config.py ├── create_tables.py ├── fill_usagi_data_tables.py ├── log.py ├── main.py ├── model │ ├── file_manager │ │ └── file_save_reponse.py │ ├── usagi │ │ ├── code_mapping_conversion.py │ │ ├── code_mapping_conversion_log.py │ │ ├── code_mapping_conversion_result.py │ │ ├── code_mapping_snapshot.py │ │ ├── conversion_status.py │ │ ├── log_status.py │ │ └── usagi_base_model.py │ ├── usagi_data │ │ ├── atc_to_rxnorm.py │ │ ├── child.py │ │ ├── code_mapping.py │ │ ├── concept.py │ │ ├── parent.py │ │ ├── relations.py │ │ ├── source_code.py │ │ └── usagi_data_base_model.py │ └── vocabulary │ │ ├── concept_vocabulary_model.py │ │ ├── source_to_concept_map.py │ │ └── vocabulary_base_model.py ├── requirements.txt ├── service │ ├── code_mapping_conversion_service.py │ ├── code_mapping_log_service.py │ ├── code_mapping_result_service.py │ ├── code_mapping_snapshot_service.py │ ├── files_manager_service.py │ ├── filters_service.py │ ├── search_service.py │ ├── similarity_score_service.py │ ├── solr_core_service.py │ ├── source_codes_service.py │ ├── source_to_concept_map_service.py │ ├── store_csv_service.py │ └── usagi_service.py ├── sshd_config ├── test │ └── util │ │ └── search_util_test.py ├── usagi-data.sql ├── usagi_api.py └── util │ ├── array_util.py │ ├── async_directive.py │ ├── code_mapping_conversion_util.py │ ├── constants.py │ ├── conversion_id.py │ ├── csv_util.py │ ├── exception.py │ ├── info_response.py │ ├── key_vaults.py │ ├── searh_util.py │ ├── target_concept_util.py │ ├── usagi_db.py │ ├── utils.py │ └── vocabulary_db.py ├── user ├── .gitignore ├── Dockerfile ├── app.py ├── app_config.py ├── authorization_api.py ├── config.py ├── create_tables.py ├── db.py ├── entrypoint.sh ├── main.py ├── model │ ├── __init__.py │ ├── baseModel.py │ ├── blacklist_token.py │ ├── refresh_token.py │ ├── unauthorized_reset_pwd_request.py │ └── user.py ├── requirements.txt ├── services │ ├── __init__.py │ ├── authorization_service.py │ └── mailout_service.py ├── sshd_config ├── user-envs.txt └── utils │ ├── __init__.py │ ├── constants.py │ ├── exceptions.py │ ├── password.py │ └── utils.py └── vocabulary-db ├── Dockerfile ├── checkout.sh ├── full.sql └── init.sql /.gitignore: -------------------------------------------------------------------------------- 1 | **.iml 2 | .idea 3 | .first_run -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /UI/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # 5 | # For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed 6 | 7 | > 0.5% 8 | last 2 versions 9 | Firefox ESR 10 | not dead 11 | not IE 9-11 -------------------------------------------------------------------------------- /UI/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://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 | -------------------------------------------------------------------------------- /UI/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /UI/Dockerfile_no-npm: -------------------------------------------------------------------------------- 1 | FROM nginx 2 | 3 | RUN apt-get update \ 4 | && apt-get install -y --no-install-recommends openssh-server \ 5 | && export ROOTPASS=$(head -c 12 /dev/urandom |base64 -) && echo "root:$ROOTPASS" | chpasswd 6 | 7 | COPY nginx.conf /etc/nginx/nginx.conf 8 | COPY dist /usr/share/nginx/html 9 | COPY sshd_config /etc/ssh/ 10 | COPY entrypoint.sh entrypoint.sh 11 | RUN chmod +x entrypoint.sh 12 | 13 | EXPOSE 4200 14 | EXPOSE 2222 15 | 16 | CMD ["./entrypoint.sh"] 17 | -------------------------------------------------------------------------------- /UI/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /UI/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /UI/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | service ssh start 4 | envsubst < /usr/share/nginx/html/assets/env.template.js > /usr/share/nginx/html/assets/env.js 5 | exec nginx -g 'daemon off;' 6 | -------------------------------------------------------------------------------- /UI/frontend-envs.txt: -------------------------------------------------------------------------------- 1 | TENANT_ID= 2 | CLIENT_ID= 3 | -------------------------------------------------------------------------------- /UI/nginx.conf: -------------------------------------------------------------------------------- 1 | events { } 2 | 3 | http { 4 | client_max_body_size 100m; 5 | include /etc/nginx/mime.types; 6 | 7 | server { 8 | listen 4200; 9 | server_name Perseus; 10 | root /usr/share/nginx/html; 11 | index index.html; 12 | 13 | location / { 14 | try_files $uri $uri/ /index.html; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /UI/src/.env: -------------------------------------------------------------------------------- 1 | NODE_PATH=src/ -------------------------------------------------------------------------------- /UI/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | -------------------------------------------------------------------------------- /UI/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | .spinner { 2 | width: 100%; 3 | height: 100%; 4 | } 5 | 6 | -------------------------------------------------------------------------------- /UI/src/app/auth.config.ts: -------------------------------------------------------------------------------- 1 | import { isDev, serverUrl } from '@app/app.constants' 2 | import { AuthConfig } from 'angular-oauth2-oidc' 3 | 4 | const env = window['envMpAYvc8QMp'] 5 | 6 | export const authConfig: AuthConfig = { 7 | issuer: `https://login.microsoftonline.com/${env?.tenantId}/v2.0`, 8 | redirectUri: `${serverUrl}`, 9 | clientId: env?.clientId, 10 | responseType: 'code', 11 | strictDiscoveryDocumentValidation: false, 12 | scope: `api://${env?.clientId}/app`, 13 | tokenEndpoint: `https://login.microsoftonline.com/${env?.tenantId}/oauth2/v2.0/token`, 14 | showDebugInformation: isDev 15 | } 16 | -------------------------------------------------------------------------------- /UI/src/app/auth/already-registered/already-registered.component.scss: -------------------------------------------------------------------------------- 1 | .already-registered__result { 2 | width: 317px; 3 | height: 275px; 4 | } 5 | -------------------------------------------------------------------------------- /UI/src/app/auth/auxiliary/auth-background/auth-background.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 | 6 |
7 | 8 |
9 | 10 |
11 |
12 | -------------------------------------------------------------------------------- /UI/src/app/auth/auxiliary/auth-background/auth-background.component.scss: -------------------------------------------------------------------------------- 1 | .auth-background { 2 | position: relative; 3 | display: flex; 4 | justify-content: center; 5 | align-items: center; 6 | width: 100%; 7 | height: 100%; 8 | background: linear-gradient(90deg, #2E2E2E 0%, #255C87 47.92%, #066BBB 100%); 9 | 10 | &__image { 11 | overflow: hidden; 12 | position: absolute; 13 | z-index: 1; 14 | inset: 0; 15 | 16 | svg { 17 | position: absolute; 18 | top: 0; 19 | right: 0; 20 | } 21 | } 22 | 23 | &__content { 24 | z-index: 2; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /UI/src/app/auth/auxiliary/auth-background/auth-background.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-auth-background', 5 | templateUrl: './auth-background.component.html', 6 | styleUrls: ['./auth-background.component.scss'] 7 | }) 8 | export class AuthBackgroundComponent { 9 | } 10 | -------------------------------------------------------------------------------- /UI/src/app/auth/auxiliary/auth-error-message/auth-error-message.component.scss: -------------------------------------------------------------------------------- 1 | @import "mixins"; 2 | 3 | .auth-error { 4 | display: flex; 5 | align-items: center; 6 | 7 | &__message { 8 | @include perseus-error-message(); 9 | text-align: center; 10 | padding-top: 1px; 11 | margin-left: 4px; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /UI/src/app/auth/auxiliary/auth-error-message/auth-error-message.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-auth-error-message', 5 | templateUrl: './auth-error-message.component.html', 6 | styleUrls: ['./auth-error-message.component.scss'] 7 | }) 8 | export class AuthErrorMessageComponent { 9 | 10 | @Input() 11 | message: string; 12 | } 13 | -------------------------------------------------------------------------------- /UI/src/app/auth/auxiliary/auth-logo/auth-logo.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-auth-logo', 5 | templateUrl: './auth-logo.component.html', 6 | styles: [ 7 | 'svg {width: 196px; height: 26px}' 8 | ] 9 | }) 10 | export class AuthLogoComponent { 11 | } 12 | -------------------------------------------------------------------------------- /UI/src/app/auth/auxiliary/auth-password-input/auth-password-input.component.scss: -------------------------------------------------------------------------------- 1 | @import "mixins"; 2 | @import "variables"; 3 | 4 | .password-wrapper { 5 | position: relative; 6 | 7 | input { 8 | width: 100%; 9 | @include login-input() 10 | } 11 | 12 | svg { 13 | position: absolute; 14 | right: 0; 15 | bottom: 8px; 16 | width: 16px; 17 | height: 8px; 18 | cursor: pointer; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /UI/src/app/auth/auxiliary/confirm-password-validator.ts: -------------------------------------------------------------------------------- 1 | import { AbstractControl, ValidatorFn } from '@angular/forms'; 2 | 3 | /** 4 | * @param password - other password input control 5 | */ 6 | export function confirmPasswordValidator(password: AbstractControl): ValidatorFn { 7 | return (control: AbstractControl): {[key: string]: any} | null => { 8 | const forbidden = control.value !== password.value 9 | return forbidden ? {message: 'Password mismatch'} : null 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /UI/src/app/auth/auxiliary/regexes.ts: -------------------------------------------------------------------------------- 1 | export const nameRegex = /^[A-Za-z]+$/ 2 | 3 | export const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d@$!%*#?&]{8,16}$/ 4 | -------------------------------------------------------------------------------- /UI/src/app/auth/auxiliary/validate-message/validate-message.component.html: -------------------------------------------------------------------------------- 1 |
2 | — 3 |
4 | 5 |
6 |
7 | -------------------------------------------------------------------------------- /UI/src/app/auth/auxiliary/validate-message/validate-message.component.scss: -------------------------------------------------------------------------------- 1 | @import "mixins"; 2 | 3 | .validate-message { 4 | padding-left: 4.5px; 5 | display: flex; 6 | @include perseus-error-message(); 7 | 8 | &__content { 9 | margin-left: 5px; 10 | flex: 1; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /UI/src/app/auth/auxiliary/validate-message/validate-message.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-validate-message', 5 | templateUrl: './validate-message.component.html', 6 | styleUrls: ['./validate-message.component.scss'] 7 | }) 8 | export class ValidateMessageComponent { 9 | } 10 | -------------------------------------------------------------------------------- /UI/src/app/auth/link-expired/link-expired.component.scss: -------------------------------------------------------------------------------- 1 | .link-expired__result { 2 | width: 317px; 3 | height: 253px; 4 | } 5 | -------------------------------------------------------------------------------- /UI/src/app/auth/recover-password/recover-password.component.scss: -------------------------------------------------------------------------------- 1 | .recover-password { 2 | &__form { 3 | width: 354px; 4 | height: 282px; 5 | } 6 | 7 | &__result { 8 | width: 354px; 9 | height: 268px; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /UI/src/app/auth/reset-password/reset-password.component.scss: -------------------------------------------------------------------------------- 1 | .reset-password { 2 | &__form { 3 | width: 354px; 4 | height: 338px; 5 | } 6 | 7 | &__result { 8 | width: 354px; 9 | height: 268px; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /UI/src/app/auth/sign-in/sign-in.component.scss: -------------------------------------------------------------------------------- 1 | @import "mixins"; 2 | @import "variables"; 3 | 4 | .sign-in { 5 | &__form { 6 | width: 354px; 7 | height: 338px; 8 | position: relative; 9 | 10 | 11 | &.add { 12 | height: 195px; 13 | } 14 | 15 | &__error { 16 | position: absolute; 17 | width: 278px; 18 | display: flex; 19 | justify-content: center; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /UI/src/app/auth/sign-out/sign-out.component.scss: -------------------------------------------------------------------------------- 1 | @import "mixins"; 2 | @import "variables"; 3 | 4 | .sign-out { 5 | &__form { 6 | width: 354px; 7 | height: 506px; 8 | } 9 | 10 | &__result { 11 | width: 354px; 12 | height: 283px; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /UI/src/app/cdm/cdm.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /UI/src/app/cdm/cdm.component.scss: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /UI/src/app/cdm/code-mapping/import-codes/column-mapping/column-mapping-form/column-mapping-form.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | @import "mixins"; 3 | 4 | .column-mapping-form { 5 | display: flex; 6 | flex-direction: column; 7 | margin-top: 15px; 8 | padding: 0 64px; 9 | 10 | &__control { 11 | @include perseus-control(); 12 | @include form-control(); 13 | margin-bottom: 20px; 14 | } 15 | } 16 | 17 | .label-required { 18 | margin-left: 3px; 19 | color: red !important; 20 | } 21 | -------------------------------------------------------------------------------- /UI/src/app/cdm/code-mapping/import-codes/import-codes.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 |
11 | -------------------------------------------------------------------------------- /UI/src/app/cdm/code-mapping/import-codes/import-codes.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | @import "mixins"; 3 | 4 | :host { 5 | width: 100%; 6 | height: calc(100% - 40px); // 40px - header height 7 | } 8 | 9 | .import-codes { 10 | width: 100%; 11 | height: 100%; 12 | } 13 | -------------------------------------------------------------------------------- /UI/src/app/cdm/code-mapping/import-codes/import-vocabulary/import-vocabulary-buttons/import-vocabulary-buttons.component.scss: -------------------------------------------------------------------------------- 1 | .import__list__item__buttons { 2 | width: 36px; 3 | display: flex; 4 | justify-content: space-between; 5 | 6 | svg { 7 | cursor: pointer; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /UI/src/app/cdm/code-mapping/import-codes/import-vocabulary/import-vocabulary-buttons/import-vocabulary-buttons.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, Output } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-import-vocabulary-buttons', 5 | templateUrl: './import-vocabulary-buttons.component.html', 6 | styleUrls: ['./import-vocabulary-buttons.component.scss'] 7 | }) 8 | export class ImportVocabularyButtonsComponent { 9 | 10 | @Output() 11 | edit = new EventEmitter() 12 | 13 | @Output() 14 | remove = new EventEmitter() 15 | } 16 | -------------------------------------------------------------------------------- /UI/src/app/cdm/code-mapping/import-codes/styles/import-codes-wrapper.scss: -------------------------------------------------------------------------------- 1 | @import "mixins"; 2 | 3 | .import-codes-wrapper { 4 | width: 100%; 5 | height: 100%; 6 | display: flex; 7 | overflow: hidden; 8 | } 9 | -------------------------------------------------------------------------------- /UI/src/app/cdm/code-mapping/mapping-codes/edit-mapping-panel/edit-code-mapping-grid/edit-code-mapping-grid.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | width: 100%; 3 | } 4 | 5 | .select-cell { 6 | width: 32px; 7 | } 8 | 9 | .header { 10 | white-space: nowrap; 11 | min-height: 32px; 12 | max-height: 32px; 13 | } 14 | -------------------------------------------------------------------------------- /UI/src/app/cdm/code-mapping/mapping-codes/save-vocabulary-popup/confirm-overwrite-vocab/confirm-overwrite-vocab.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | @import "mixins"; 3 | 4 | .confirm-overwrite-dialog { 5 | @include perseus-popup(); 6 | 7 | p { 8 | font-weight: 500; 9 | font-size: 16px; 10 | line-height: 21px; 11 | text-align: center; 12 | } 13 | 14 | &__actions { 15 | margin-top: 25px; 16 | display: flex; 17 | justify-content: space-around; 18 | 19 | button { 20 | @include cdm-button(); 21 | width: 80px; 22 | height: 30px; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /UI/src/app/cdm/code-mapping/mapping-codes/save-vocabulary-popup/confirm-overwrite-vocab/confirm-overwrite-vocab.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { MatDialogRef } from '@angular/material/dialog'; 3 | 4 | @Component({ 5 | selector: 'app-confirm-overwrite-vocab', 6 | templateUrl: './confirm-overwrite-vocab.component.html', 7 | styleUrls: ['./confirm-overwrite-vocab.component.scss'] 8 | }) 9 | export class ConfirmOverwriteVocabComponent { 10 | 11 | constructor(public dialogRef: MatDialogRef) { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /UI/src/app/cdm/comfy/columns-list/column-list.ts: -------------------------------------------------------------------------------- 1 | export function getPositionStrategy(element: HTMLElement, listHalfHeight: number, listTop: number) { 2 | const {top} = element.getBoundingClientRect(); 3 | const relativeTop = top - listTop 4 | 5 | return listHalfHeight > relativeTop ? 'top' : 'bottom'; 6 | } 7 | -------------------------------------------------------------------------------- /UI/src/app/cdm/comfy/comfy-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { RouterModule, Routes } from '@angular/router'; 2 | import { NgModule } from '@angular/core'; 3 | import { ComfyComponent } from './comfy.component'; 4 | 5 | const routes: Routes = [ 6 | { 7 | path: '', 8 | component: ComfyComponent, 9 | data: { breadcrumb: 'Link Tables' }, 10 | } 11 | ]; 12 | 13 | @NgModule({ 14 | imports: [RouterModule.forChild(routes)], 15 | exports: [RouterModule] 16 | }) 17 | export class ComfyRoutingModule { 18 | } 19 | -------------------------------------------------------------------------------- /UI/src/app/cdm/mapping/concept-transformation/concept-column/concept-column.component.scss: -------------------------------------------------------------------------------- 1 | .error-icon { 2 | color: red; 3 | font-size: 17px; 4 | height: 17px; 5 | width: 17px; 6 | padding-left: 7px; 7 | cursor: pointer; 8 | } 9 | 10 | .text-label { 11 | width: calc(100% - 25px); 12 | } 13 | -------------------------------------------------------------------------------- /UI/src/app/cdm/mapping/mapping-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { RouterModule, Routes } from '@angular/router'; 2 | import { NgModule } from '@angular/core'; 3 | import { MappingComponent } from './mapping.component'; 4 | 5 | const routes: Routes = [ 6 | { 7 | path: '', 8 | component: MappingComponent, 9 | data: { breadcrumb: 'Link Fields' } 10 | } 11 | ]; 12 | 13 | @NgModule({ 14 | imports: [RouterModule.forChild(routes)], 15 | exports: [RouterModule] 16 | }) 17 | export class MappingRoutingModule { 18 | } 19 | -------------------------------------------------------------------------------- /UI/src/app/cdm/mapping/panel/area/area.component.html: -------------------------------------------------------------------------------- 1 |
9 | 10 |
11 | -------------------------------------------------------------------------------- /UI/src/app/cdm/mapping/panel/panel-table/similar-types.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "CHAR": [ 4 | "VARCHAR", 5 | "NVARCHAR", 6 | "CHARACTER", 7 | "CHARACTER VARYING", 8 | "CHAR", 9 | "TEXT" 10 | ], 11 | 12 | "INT": [ 13 | "INT", 14 | "BIGINT", 15 | "SMALLINT", 16 | "INTEGER" 17 | ], 18 | 19 | "BOOLEAN": ["BOOLEAN"], 20 | 21 | "DATE": ["DATE"], 22 | 23 | "FLOAT": [ 24 | "REAL", 25 | "DECIMAL", 26 | "DOUBLE PRECISION"] 27 | 28 | } -------------------------------------------------------------------------------- /UI/src/app/cdm/mapping/panel/target-clone-dialog/target-clone-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .flex{ 2 | display: flex; 3 | font-size: 15px; 4 | margin-bottom: 10px; 5 | } 6 | 7 | .upper-blue{ 8 | text-transform: uppercase; 9 | color: #066BBB; 10 | } 11 | 12 | .margin{ 13 | margin-right: 5px; 14 | } 15 | 16 | .height-85{ 17 | height: 85px !important; 18 | } -------------------------------------------------------------------------------- /UI/src/app/cdm/mapping/sql-transformation/sql-transformation.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | @import "mixins"; 3 | 4 | .sql-transformation { 5 | &__mode { 6 | position: relative; 7 | @include radio-button(); 8 | width: 150px; 9 | margin-bottom: 26px; 10 | padding-top: 5px; 11 | 12 | &__hint { 13 | position: absolute; 14 | top: 0; 15 | right: -19px; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /UI/src/app/cdm/mapping/sql-transformation/visual-transformation/function/date-add-transformation-function/date-add-transformation-function.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | {{part}} 5 | 6 | 7 | 8 | 9 |
10 | -------------------------------------------------------------------------------- /UI/src/app/cdm/mapping/sql-transformation/visual-transformation/function/date-add-transformation-function/date-add-transformation-function.component.scss: -------------------------------------------------------------------------------- 1 | @import "mixins"; 2 | 3 | :host { 4 | @include transformation-function(); 5 | } 6 | 7 | .date-add { 8 | @include transformation-function-toolbar(); 9 | display: flex; 10 | justify-content: space-between; 11 | 12 | input, 13 | .mat-select { 14 | @include cdm-input(); 15 | background: none; 16 | width: 120px; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /UI/src/app/cdm/mapping/sql-transformation/visual-transformation/function/date-part-transformation-function/date-part-transformation-function.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | {{part}} 5 | 6 | 7 |
8 | -------------------------------------------------------------------------------- /UI/src/app/cdm/mapping/sql-transformation/visual-transformation/function/date-part-transformation-function/date-part-transformation-function.component.scss: -------------------------------------------------------------------------------- 1 | @import "mixins"; 2 | 3 | :host { 4 | @include transformation-function(); 5 | } 6 | 7 | .date-part { 8 | @include transformation-function-toolbar(); 9 | display: flex; 10 | 11 | .mat-select { 12 | @include cdm-input(); 13 | background: none; 14 | width: 120px; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /UI/src/app/cdm/mapping/sql-transformation/visual-transformation/function/no-args-transformation-function/function/lower-transformation-function.ts: -------------------------------------------------------------------------------- 1 | import { NoArgsTransformationFunction } from '@mapping/sql-transformation/visual-transformation/function/no-args-transformation-function/no-args-transformation-function'; 2 | 3 | export class LowerTransformationFunction extends NoArgsTransformationFunction { 4 | 5 | sql(): (arg: string) => string { 6 | return arg => `LOWER(${arg})` 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /UI/src/app/cdm/mapping/sql-transformation/visual-transformation/function/no-args-transformation-function/function/trim-transformation-function.ts: -------------------------------------------------------------------------------- 1 | import { NoArgsTransformationFunction } from '@mapping/sql-transformation/visual-transformation/function/no-args-transformation-function/no-args-transformation-function'; 2 | 3 | export class TrimTransformationFunction extends NoArgsTransformationFunction { 4 | 5 | sql(): (arg: string) => string { 6 | return (arg: string) => `TRIM(${arg})`; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /UI/src/app/cdm/mapping/sql-transformation/visual-transformation/function/no-args-transformation-function/function/upper-transformation-function.ts: -------------------------------------------------------------------------------- 1 | import { NoArgsTransformationFunction } from '@mapping/sql-transformation/visual-transformation/function/no-args-transformation-function/no-args-transformation-function'; 2 | 3 | export class UpperTransformationFunction extends NoArgsTransformationFunction { 4 | 5 | sql(): (arg: string) => string { 6 | return (arg: string) => `UPPER(${arg})`; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /UI/src/app/cdm/mapping/sql-transformation/visual-transformation/function/no-args-transformation-function/no-args-transformation-function.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | template: '' 5 | }) 6 | export class NoArgsTransformationFunctionComponent { 7 | } 8 | -------------------------------------------------------------------------------- /UI/src/app/cdm/mapping/sql-transformation/visual-transformation/function/transformation-function.component.ts: -------------------------------------------------------------------------------- 1 | import { TransformationFunction } from '@mapping/sql-transformation/visual-transformation/function/transformation-function'; 2 | 3 | export abstract class TransformationFunctionComponent { 4 | 5 | protected constructor(protected transformationFunction: TransformationFunction) { 6 | } 7 | 8 | get function() { 9 | return this.transformationFunction 10 | } 11 | 12 | get form() { 13 | return this.transformationFunction.form 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /UI/src/app/grid/auxiliary/grid-column/grid-column.component.scss: -------------------------------------------------------------------------------- 1 | .sortable-column { 2 | width: 100%; 3 | display: flex; 4 | justify-content: space-between; 5 | 6 | svg { 7 | margin-left: 12px; 8 | cursor: pointer; 9 | visibility: hidden; 10 | } 11 | 12 | &:hover { 13 | svg { 14 | visibility: visible; 15 | } 16 | } 17 | 18 | &.sortable-asc, 19 | &.sortable-desc { 20 | svg { 21 | display: block; 22 | } 23 | } 24 | 25 | &.sortable-desc { 26 | svg { 27 | transform: scale(1, -1); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /UI/src/app/grid/selectable-grid/grid-checkbox/grid-checkbox.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
6 | -------------------------------------------------------------------------------- /UI/src/app/grid/selectable-grid/grid-checkbox/grid-checkbox.component.scss: -------------------------------------------------------------------------------- 1 | .checkbox { 2 | width: 16px; 3 | height: 16px; 4 | border: 1px solid #8B8B8B; 5 | box-sizing: border-box; 6 | border-radius: 1px; 7 | display: flex; 8 | justify-content: center; 9 | align-items: center; 10 | padding-left: 1px; 11 | cursor: pointer; 12 | margin: 0 auto; 13 | 14 | svg { 15 | display: none; 16 | } 17 | 18 | &.checked { 19 | background: rgba(6, 107, 187, 0.2); 20 | 21 | svg { 22 | display: block; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /UI/src/app/grid/selectable-grid/grid-checkbox/grid-checkbox.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-grid-checkbox', 5 | templateUrl: './grid-checkbox.component.html', 6 | styleUrls: ['./grid-checkbox.component.scss'] 7 | }) 8 | export class GridCheckboxComponent { 9 | 10 | @Input() 11 | checked = false 12 | } 13 | -------------------------------------------------------------------------------- /UI/src/app/grid/selectable-grid/selectable-grid.component.scss: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /UI/src/app/infrastructure/command.ts: -------------------------------------------------------------------------------- 1 | import { yes, noop } from './utility'; 2 | 3 | export class ICommandContext { 4 | execute?: (arg?: T) => any; 5 | canExecute?: (arg?: T) => boolean; 6 | } 7 | 8 | export class Command { 9 | execute: (arg?: T) => K = noop as any; 10 | canExecute: (arg?: T) => any = yes; 11 | 12 | constructor(context: ICommandContext = {}) { 13 | Object.assign(this, context); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /UI/src/app/models/area.ts: -------------------------------------------------------------------------------- 1 | export enum Area { 2 | Source = 'source', 3 | Target = 'target', 4 | SourceColumn= 'source-column' 5 | } 6 | 7 | -------------------------------------------------------------------------------- /UI/src/app/models/arrow-cache.ts: -------------------------------------------------------------------------------- 1 | import { Connection, IConnection } from '@models/connection'; 2 | import { Type } from 'class-transformer'; 3 | 4 | /* 5 | * key - `${sourceTableId}-${sourceRowId}/${targetTableId}-${targetRowId}` 6 | **/ 7 | export interface IArrowCache { 8 | [key: string]: IConnection; 9 | } 10 | 11 | export class ArrowCache implements IArrowCache { 12 | // @ts-ignore 13 | @Type(() => Connection) 14 | [key: string]: IConnection; 15 | } 16 | -------------------------------------------------------------------------------- /UI/src/app/models/auth/user.ts: -------------------------------------------------------------------------------- 1 | export interface User { 2 | username: string; 3 | email: string; 4 | password?: string; 5 | token?: string; 6 | firstName?: string; 7 | lastName?: string; 8 | refresh_token?: string; 9 | } 10 | -------------------------------------------------------------------------------- /UI/src/app/models/cdm-builder/cdm-builder-status.ts: -------------------------------------------------------------------------------- 1 | export enum CdmBuilderStatus { 2 | IDLE = 'Idle', 3 | RUNNING = 'Running', 4 | ABORTED = 'Aborted' 5 | } 6 | -------------------------------------------------------------------------------- /UI/src/app/models/clones.ts: -------------------------------------------------------------------------------- 1 | import { ITable, Table } from '@models/table'; 2 | 3 | export interface IClones { 4 | [key: string]: ITable[] 5 | } 6 | 7 | export class Clones implements IClones { 8 | // @ts-ignore 9 | @Type(() => Table) 10 | [key: string]: ITable[] 11 | } 12 | 13 | export const DEFAULT_CLONE = 'Default' 14 | -------------------------------------------------------------------------------- /UI/src/app/models/code-mapping/code-mapping-params.ts: -------------------------------------------------------------------------------- 1 | export interface CodeMappingParams { 2 | sourceCode?: string 3 | sourceName: string // Term column using for search concepts 4 | sourceFrequency?: string 5 | columnType?: string 6 | autoConceptId?: string 7 | additionalInfo?: string 8 | } 9 | -------------------------------------------------------------------------------- /UI/src/app/models/code-mapping/code.ts: -------------------------------------------------------------------------------- 1 | export interface Code { 2 | selected: boolean 3 | [key: string]: any 4 | } 5 | -------------------------------------------------------------------------------- /UI/src/app/models/code-mapping/concept.ts: -------------------------------------------------------------------------------- 1 | export interface Concept { 2 | conceptId: number | string 3 | conceptName: string 4 | domainId: string 5 | conceptClassId: string 6 | vocabularyId: string 7 | conceptCode: number | string 8 | standardConcept: string 9 | index?: number 10 | term?: string 11 | } 12 | 13 | export function createNoFoundConcept(): Concept { 14 | return { 15 | conceptId: '-', 16 | conceptName: '-', 17 | domainId: '-', 18 | conceptClassId: '-', 19 | vocabularyId: '-', 20 | conceptCode: '-', 21 | standardConcept: '-' 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /UI/src/app/models/code-mapping/console-header.ts: -------------------------------------------------------------------------------- 1 | export enum ConsoleHeader { 2 | CALCULATE_SCORE = 'Calculating Scores', 3 | LOAD_VOCABULARY = 'Loading Vocabulary' 4 | } 5 | -------------------------------------------------------------------------------- /UI/src/app/models/code-mapping/scored-concept-cache.ts: -------------------------------------------------------------------------------- 1 | import { ScoredConcept } from './scored-concept'; 2 | import { SearchConceptFilters } from './search-concept-filters'; 3 | import { SearchMode } from './search-mode'; 4 | 5 | export interface ScoredConceptCache { 6 | concepts: ScoredConcept[], 7 | filters: SearchConceptFilters, 8 | searchMode: SearchMode 9 | } 10 | -------------------------------------------------------------------------------- /UI/src/app/models/code-mapping/scored-concept.ts: -------------------------------------------------------------------------------- 1 | import { Selectable } from '../grid/selectable'; 2 | import { Concept } from './concept'; 3 | 4 | export class ScoredConcept implements Selectable { 5 | term: string[] 6 | matchScore: number 7 | concept: Concept 8 | selected: boolean 9 | } 10 | -------------------------------------------------------------------------------- /UI/src/app/models/code-mapping/search-by-term-params.ts: -------------------------------------------------------------------------------- 1 | import { Concept } from './concept'; 2 | 3 | export interface SearchByTermParams { 4 | term: string, 5 | selectedConcepts: Concept[], 6 | sourceAutoAssignedConceptIds: number[] 7 | } 8 | -------------------------------------------------------------------------------- /UI/src/app/models/code-mapping/search-mode.ts: -------------------------------------------------------------------------------- 1 | export enum SearchMode { 2 | SEARCH_TERM_AS_QUERY = 'term', 3 | QUERY = 'query' 4 | } 5 | -------------------------------------------------------------------------------- /UI/src/app/models/code-mapping/source-code.ts: -------------------------------------------------------------------------------- 1 | import { Code } from './code'; 2 | 3 | export interface SourceCode { 4 | code: Code 5 | source_name?: string 6 | source_auto_assigned_concept_ids?: number[] 7 | } 8 | -------------------------------------------------------------------------------- /UI/src/app/models/code-mapping/target-concept.ts: -------------------------------------------------------------------------------- 1 | import { Concept } from './concept'; 2 | 3 | export interface TargetConcept { 4 | concept: Concept 5 | term: string[] 6 | } 7 | 8 | export function termFromTargetConcept(concept: TargetConcept) { 9 | return concept.term?.find(() => true) 10 | } 11 | -------------------------------------------------------------------------------- /UI/src/app/models/comment.ts: -------------------------------------------------------------------------------- 1 | export interface IComment { 2 | id: number; 3 | text: string; 4 | 5 | newValue(value: string): void; 6 | } 7 | 8 | export class Comment implements IComment { 9 | id: number; 10 | text: string; 11 | 12 | constructor( 13 | text: string 14 | ) { 15 | this.id = Math.floor(Math.random() * 1000000); 16 | this.text = text; 17 | } 18 | 19 | newValue(value: string) { 20 | this.text = value; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /UI/src/app/models/const-event.ts: -------------------------------------------------------------------------------- 1 | export enum ConstEvent { 2 | ADD = 'add', 3 | DROP = 'drop' 4 | } 5 | -------------------------------------------------------------------------------- /UI/src/app/models/constant-cache.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * key - `${sourceTableId}/${targetTableId}-${targetRowId}` 3 | **/ 4 | import { IRow, Row } from '@models/row'; 5 | 6 | export interface IConstantCache { 7 | [key: string]: IRow; 8 | } 9 | 10 | export class ConstantCache implements IConstantCache { 11 | // @ts-ignore 12 | @Type(() => Row) 13 | [key: string]: IRow; 14 | } 15 | -------------------------------------------------------------------------------- /UI/src/app/models/conversion/conversion-status.ts: -------------------------------------------------------------------------------- 1 | export enum ConversionStatus { 2 | IN_PROGRESS = 1, 3 | COMPLETED = 2, 4 | ABORTED = 3, 5 | FAILED = 4 6 | } 7 | -------------------------------------------------------------------------------- /UI/src/app/models/conversion/conversion.ts: -------------------------------------------------------------------------------- 1 | import { ProgressLog } from '@models/progress-console/progress-log' 2 | 3 | export interface Conversion { 4 | id: number 5 | project: string 6 | statusCode: number, 7 | statusName: string 8 | logs: ProgressLog[] 9 | } 10 | -------------------------------------------------------------------------------- /UI/src/app/models/filter/filter.ts: -------------------------------------------------------------------------------- 1 | export interface Filter { 2 | name: string; 3 | field: string; 4 | color?: string; 5 | values?: FilterValue[]; 6 | checkboxField?: string; 7 | } 8 | 9 | export interface FilterValue { 10 | name: string; 11 | count?: number; 12 | filterIndex?: number; // Parent index 13 | disabled: boolean; 14 | checked?: boolean 15 | } 16 | -------------------------------------------------------------------------------- /UI/src/app/models/filtered-fields.ts: -------------------------------------------------------------------------------- 1 | export interface FilteredFields { 2 | [targetTableName: string]: FilteredField 3 | } 4 | 5 | export interface FilteredField { 6 | checkedTypes: string[], 7 | items: string[], 8 | types: string[] 9 | } 10 | -------------------------------------------------------------------------------- /UI/src/app/models/grid/grid.ts: -------------------------------------------------------------------------------- 1 | export interface Column { 2 | field: string; 3 | name: string; 4 | width?: string; 5 | className?: string; 6 | sortable?: boolean 7 | } 8 | 9 | export interface Sort { 10 | field: string; 11 | order: 'asc' | 'desc'; 12 | } 13 | 14 | export const columnToField = (column: Column) => column.field 15 | -------------------------------------------------------------------------------- /UI/src/app/models/grid/pagination.ts: -------------------------------------------------------------------------------- 1 | export interface Pagination { 2 | pageCount: number, 3 | pageNumber: number 4 | } 5 | -------------------------------------------------------------------------------- /UI/src/app/models/grid/selectable.ts: -------------------------------------------------------------------------------- 1 | export interface Selectable { 2 | selected: boolean 3 | } 4 | -------------------------------------------------------------------------------- /UI/src/app/models/perseus/column-info-response.ts: -------------------------------------------------------------------------------- 1 | export interface ColumnInfoResponse { 2 | column_name: string 3 | column_type: string 4 | is_column_nullable: string 5 | } 6 | -------------------------------------------------------------------------------- /UI/src/app/models/perseus/column-info.ts: -------------------------------------------------------------------------------- 1 | export interface ValueInfo { 2 | value: string; 3 | frequency: string; 4 | percentage: string; 5 | } 6 | 7 | export interface ColumnInfo { 8 | type?: string; 9 | uniqueValues?: string; 10 | topValues?: ValueInfo[]; 11 | } 12 | 13 | export enum ColumnInfoStatus { 14 | LOADING, 15 | READY, 16 | NO_INFO 17 | } 18 | -------------------------------------------------------------------------------- /UI/src/app/models/perseus/concept-field.ts: -------------------------------------------------------------------------------- 1 | export interface IConceptField { 2 | field: string; 3 | targetFieldName: string; 4 | targetCloneName: string; 5 | sql: string; 6 | sqlApplied: boolean; 7 | constant: string; 8 | selected: boolean; 9 | constantSelected: boolean; 10 | condition: string; 11 | alreadySelected: boolean; 12 | } 13 | 14 | export interface IConceptFields { 15 | concept_id: IConceptField; 16 | source_value: IConceptField; 17 | source_concept_id: IConceptField; 18 | type_concept_id: IConceptField; 19 | } 20 | -------------------------------------------------------------------------------- /UI/src/app/models/perseus/concept-lookup.ts: -------------------------------------------------------------------------------- 1 | import { LookupForEtlConfiguration } from '@models/perseus/lookup' 2 | 3 | export interface IConceptLookup { 4 | [key: string]: LookupForEtlConfiguration 5 | } 6 | 7 | export class ConceptLookup implements IConceptLookup { 8 | // @ts-ignore 9 | @Type(() => SimplifiedLookup) 10 | [key: string]: LookupForEtlConfiguration 11 | } 12 | -------------------------------------------------------------------------------- /UI/src/app/models/perseus/concept.ts: -------------------------------------------------------------------------------- 1 | import { IConceptFields } from '@models/perseus/concept-field' 2 | 3 | export interface IConcept { 4 | id: number; 5 | fields: IConceptFields; 6 | } 7 | 8 | export interface IConceptOptions { 9 | id?: number; 10 | fields?: IConceptFields; 11 | } 12 | 13 | export class Concept implements IConcept { 14 | id: number; 15 | fields: IConceptFields; 16 | 17 | constructor(options: IConceptOptions = {}) { 18 | this.id = options.id; 19 | this.fields = options.fields; 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /UI/src/app/models/perseus/concepts.ts: -------------------------------------------------------------------------------- 1 | import { ConceptTables } from '@models/perseus/concept-tables' 2 | 3 | export interface IConcepts { 4 | [key: string]: ConceptTables 5 | } 6 | 7 | export class Concepts implements IConcepts { 8 | // @ts-ignore 9 | @Type(() => ConceptTables) 10 | [key: string]: ConceptTables 11 | } 12 | -------------------------------------------------------------------------------- /UI/src/app/models/perseus/etl-mapping.ts: -------------------------------------------------------------------------------- 1 | export interface EtlMapping { 2 | id: number 3 | username: string 4 | source_schema_name: string 5 | cdm_version: string 6 | scan_report_name: string 7 | scan_report_id: number 8 | } 9 | -------------------------------------------------------------------------------- /UI/src/app/models/perseus/generate-etl-archive-request.ts: -------------------------------------------------------------------------------- 1 | import { EtlConfiguration } from '@models/etl-configuration' 2 | 3 | export interface GenerateEtlArchiveRequest { 4 | name: string 5 | etl_mapping_id: number 6 | etl_configuration: Record 7 | } 8 | -------------------------------------------------------------------------------- /UI/src/app/models/perseus/lookup-list-item.ts: -------------------------------------------------------------------------------- 1 | export interface LookupListItem { 2 | id?: number, 3 | name: string 4 | } 5 | -------------------------------------------------------------------------------- /UI/src/app/models/perseus/lookup-request.ts: -------------------------------------------------------------------------------- 1 | export interface LookupRequest { 2 | name: string 3 | source_to_standard: string 4 | source_to_source: string 5 | } 6 | -------------------------------------------------------------------------------- /UI/src/app/models/perseus/lookup-type.ts: -------------------------------------------------------------------------------- 1 | export type LookupType = 'source_to_standard' | 'source_to_source' 2 | -------------------------------------------------------------------------------- /UI/src/app/models/perseus/lookup.ts: -------------------------------------------------------------------------------- 1 | export interface Lookup { 2 | id?: number 3 | name?: string 4 | updatedName?: string 5 | originName?: string 6 | lookupType?: string 7 | value?: string 8 | 9 | isUserDefined?: boolean 10 | applied?: boolean 11 | sourceToSourceIncluded?: boolean 12 | source_to_source?: string 13 | source_to_standard?: string 14 | } 15 | 16 | export interface LookupForEtlConfiguration { 17 | id: number | null 18 | name: string 19 | lookupType: string, 20 | sourceToSourceIncluded: boolean, 21 | applied?: boolean 22 | } 23 | -------------------------------------------------------------------------------- /UI/src/app/models/perseus/scan-report-request.ts: -------------------------------------------------------------------------------- 1 | export interface ScanReportRequest { 2 | dataId: number 3 | fileName: string 4 | cdmVersion?: string 5 | } 6 | -------------------------------------------------------------------------------- /UI/src/app/models/perseus/table-info-response.ts: -------------------------------------------------------------------------------- 1 | import { ColumnInfoResponse } from '@models/perseus/column-info-response' 2 | 3 | export interface TableInfoResponse { 4 | table_name: string 5 | column_list: ColumnInfoResponse[] 6 | } 7 | -------------------------------------------------------------------------------- /UI/src/app/models/perseus/upload-etl-mapping-response.ts: -------------------------------------------------------------------------------- 1 | import { EtlConfiguration } from '@models/etl-configuration' 2 | import { EtlMapping } from '@models/perseus/etl-mapping' 3 | 4 | export interface UploadEtlMappingResponse { 5 | etl_mapping: EtlMapping 6 | etl_configuration: Record 7 | } 8 | -------------------------------------------------------------------------------- /UI/src/app/models/perseus/upload-scan-report-response.ts: -------------------------------------------------------------------------------- 1 | import { EtlMapping } from '@models/perseus/etl-mapping' 2 | import { TableInfoResponse } from '@models/perseus/table-info-response' 3 | 4 | export interface UploadScanReportResponse { 5 | etl_mapping: EtlMapping 6 | source_tables: TableInfoResponse[] 7 | } 8 | -------------------------------------------------------------------------------- /UI/src/app/models/perseus/view-sql-response.ts: -------------------------------------------------------------------------------- 1 | export interface ViewSqlResponse { 2 | name: string 3 | type: string 4 | } 5 | -------------------------------------------------------------------------------- /UI/src/app/models/popup/save-model.ts: -------------------------------------------------------------------------------- 1 | import { Observable } from 'rxjs'; 2 | 3 | export interface SaveModel { 4 | header: string, 5 | label: string, 6 | okButton: string, 7 | type: string, 8 | errorMessage: string, 9 | items: any[] 10 | existingNames: any[] 11 | save$?: (payload: string) => Observable 12 | } 13 | -------------------------------------------------------------------------------- /UI/src/app/models/progress-console/progress-log-status.ts: -------------------------------------------------------------------------------- 1 | export enum ProgressLogStatus { 2 | INFO = 1, 3 | DEBUG = 2, 4 | WARNING = 3, 5 | ERROR = 4 6 | } 7 | -------------------------------------------------------------------------------- /UI/src/app/models/progress-console/progress-log.ts: -------------------------------------------------------------------------------- 1 | import { ProgressLogStatus } from '@models/progress-console/progress-log-status' 2 | 3 | export interface ProgressLog { 4 | message: string 5 | statusCode: ProgressLogStatus 6 | statusName: string 7 | percent: number 8 | } 9 | -------------------------------------------------------------------------------- /UI/src/app/models/reset-warning-data.ts: -------------------------------------------------------------------------------- 1 | export interface ResetWarningData { 2 | header: string 3 | warning: string 4 | okButton: string 5 | deleteButton: string 6 | } 7 | -------------------------------------------------------------------------------- /UI/src/app/models/scan-data/scan-result.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @deprecated 3 | */ 4 | export enum ScanStatus { 5 | IN_PROGRESS, 6 | SUCCESSFULLY, 7 | FAILED 8 | } 9 | 10 | /** 11 | * @deprecated 12 | */ 13 | export interface ScanResult { 14 | status: ScanStatus, 15 | payload?: T 16 | } 17 | -------------------------------------------------------------------------------- /UI/src/app/models/scan-data/state.ts: -------------------------------------------------------------------------------- 1 | export interface IScanDataStateService { 2 | state: any; 3 | } 4 | -------------------------------------------------------------------------------- /UI/src/app/models/sql-functions-injector.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken } from '@angular/core'; 2 | import { SqlFunction } from '@models/transformation-input/sql-string-functions' 3 | 4 | export const SqlFunctionsInjector = new InjectionToken>( 5 | 'SQL_FUCTIONS' 6 | ); 7 | -------------------------------------------------------------------------------- /UI/src/app/models/target-config.ts: -------------------------------------------------------------------------------- 1 | export interface TargetConfig { 2 | [targetTableName: string]: TargetConfigItem 3 | } 4 | 5 | export interface TargetConfigItem { 6 | name: string, // Target table name 7 | first: string, 8 | data: string[] // Mapped source tables 9 | } 10 | -------------------------------------------------------------------------------- /UI/src/app/models/transformation-dialog-data.ts: -------------------------------------------------------------------------------- 1 | import { IConnector } from '@models/connector'; 2 | import { IArrowCache } from '@models/arrow-cache'; 3 | import { Lookup } from '@models/perseus/lookup' 4 | import { SqlForTransformation } from '@models/transformation/sql-for-transformation' 5 | import { LookupType } from '@models/perseus/lookup-type' 6 | 7 | export interface TransformationDialogData { 8 | connector: IConnector 9 | arrowCache: IArrowCache 10 | lookup: Lookup 11 | lookupType: LookupType, 12 | sql: SqlForTransformation, 13 | tab: string 14 | } 15 | -------------------------------------------------------------------------------- /UI/src/app/models/transformation-dialog-result.ts: -------------------------------------------------------------------------------- 1 | import { Lookup } from '@models/perseus/lookup' 2 | import { SqlForTransformation } from '@models/transformation/sql-for-transformation' 3 | 4 | export interface TransformationDialogResult { 5 | lookup?: Lookup 6 | sql?: SqlForTransformation 7 | } 8 | -------------------------------------------------------------------------------- /UI/src/app/models/transformation/datepart.ts: -------------------------------------------------------------------------------- 1 | export type DatePart = 'Year' | 'Month' | 'Day' | 'Hour' | 'Minute' | 'Second' 2 | 3 | export const dateParts = [ 4 | 'Year', 5 | 'Month', 6 | 'Day', 7 | 'Hour', 8 | 'Minute', 9 | 'Second', 10 | ] 11 | -------------------------------------------------------------------------------- /UI/src/app/models/transformation/function-type.ts: -------------------------------------------------------------------------------- 1 | export enum FunctionType { 2 | REPLACE = 'REPLACE', 3 | DATEPART = 'DATEPART', 4 | DATEADD = 'DATEADD', 5 | CASE = 'CASE', 6 | TRIM = 'TRIM', 7 | UPPER = 'UPPER', 8 | LOWER = 'LOWER' 9 | } 10 | -------------------------------------------------------------------------------- /UI/src/app/models/transformation/sql-for-transformation.ts: -------------------------------------------------------------------------------- 1 | import { SqlFunctionForTransformationState } from '@models/transformation/sql-function-for-transformation'; 2 | import { SqlTransformMode } from '@models/transformation/sql-transform-mode'; 3 | 4 | export interface SqlForTransformation { 5 | applied?: boolean 6 | name?: string // For Manual sql 7 | functions?: SqlFunctionForTransformationState[] // For Visual sql 8 | mode?: SqlTransformMode 9 | } 10 | -------------------------------------------------------------------------------- /UI/src/app/models/transformation/sql-transform-mode.ts: -------------------------------------------------------------------------------- 1 | export type SqlTransformMode = 'visual' | 'manual' 2 | -------------------------------------------------------------------------------- /UI/src/app/models/vocabulary-search/concept.ts: -------------------------------------------------------------------------------- 1 | export interface Concept { 2 | id: number; 3 | code: string; 4 | name: string; 5 | className: string; 6 | standardConcept: string; 7 | invalidReason: string; 8 | domain: string; 9 | vocabulary: string; 10 | } 11 | -------------------------------------------------------------------------------- /UI/src/app/models/white-rabbit/connection-result.ts: -------------------------------------------------------------------------------- 1 | import { TableToScan } from '@models/white-rabbit/table-to-scan' 2 | 3 | export interface ConnectionResult { 4 | canConnect: boolean 5 | message?: string 6 | } 7 | 8 | export interface WrConnectionResult extends ConnectionResult { 9 | canConnect: boolean 10 | message?: string 11 | tableNames?: string[] 12 | tablesToScan: TableToScan[] 13 | } 14 | -------------------------------------------------------------------------------- /UI/src/app/models/white-rabbit/data-type-group.ts: -------------------------------------------------------------------------------- 1 | export interface DataTypeGroup { 2 | name: string 3 | value: string[] 4 | } 5 | -------------------------------------------------------------------------------- /UI/src/app/models/white-rabbit/fake-data-request.ts: -------------------------------------------------------------------------------- 1 | import { FakeDataSettings } from '@models/white-rabbit/fake-data-settings' 2 | import { ScanReportRequest } from '@models/perseus/scan-report-request' 3 | 4 | export interface FakeDataRequest { 5 | settings: FakeDataSettings 6 | scanReportInfo: ScanReportRequest 7 | } 8 | -------------------------------------------------------------------------------- /UI/src/app/models/white-rabbit/fake-data-settings.ts: -------------------------------------------------------------------------------- 1 | export interface FakeDataSettings { 2 | maxRowCount: number; 3 | doUniformSampling: boolean; 4 | userSchema?: string 5 | } 6 | -------------------------------------------------------------------------------- /UI/src/app/models/white-rabbit/scan-data-params.ts: -------------------------------------------------------------------------------- 1 | export interface ScanDataParams { 2 | sampleSize: number; 3 | scanValues: boolean; 4 | minCellCount: number; 5 | maxValues: number; 6 | calculateNumericStats: boolean; 7 | numericStatsSamplerSize: number; 8 | } 9 | -------------------------------------------------------------------------------- /UI/src/app/models/white-rabbit/scan-settings-type.ts: -------------------------------------------------------------------------------- 1 | export enum ScanSettingsType { 2 | DB, 3 | FILES 4 | } 5 | -------------------------------------------------------------------------------- /UI/src/app/models/white-rabbit/scan-settings.ts: -------------------------------------------------------------------------------- 1 | import { ScanDataParams } from './scan-data-params'; 2 | 3 | export interface ScanSettings { 4 | scanDataParams?: ScanDataParams; 5 | } 6 | -------------------------------------------------------------------------------- /UI/src/app/models/white-rabbit/table-to-scan.ts: -------------------------------------------------------------------------------- 1 | export interface TableToScan { 2 | tableName: string; 3 | selected: boolean; 4 | } 5 | -------------------------------------------------------------------------------- /UI/src/app/popups/cdm-filter/cdm-filter.component.html: -------------------------------------------------------------------------------- 1 |

Filter {{title}}

2 | 4 | 9 | {{item}} 10 | 11 | 12 | -------------------------------------------------------------------------------- /UI/src/app/popups/cdm-filter/cdm-filter.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | background-color: white; 4 | .mat-list-base { 5 | padding-top: 0; 6 | .mat-list-item-content { 7 | padding: 0; 8 | } 9 | } 10 | } 11 | 12 | .option-text { 13 | text-transform: capitalize; 14 | font-size: 14px; 15 | } 16 | 17 | .filter-header { 18 | margin: 8px 16px 0 16px; 19 | font-size: 14px; 20 | } 21 | 22 | .mat-list-option{ 23 | height: 35px !important; 24 | padding-right: 60px !important; 25 | } 26 | 27 | .mat-selection-list{ 28 | padding-bottom: 10px; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /UI/src/app/popups/cdm-version-dialog/cdm-version-dialog.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | } 4 | 5 | -------------------------------------------------------------------------------- /UI/src/app/popups/delete-warning/delete-warning.component.html: -------------------------------------------------------------------------------- 1 |

Delete {{title}}

2 | close 3 | {{message}}. This action cannot be undone! 4 | 5 | 12 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /UI/src/app/popups/delete-warning/delete-warning.component.scss: -------------------------------------------------------------------------------- 1 | @import '../../styles/variables'; 2 | 3 | :host { 4 | display: block; 5 | } 6 | 7 | .label { 8 | display: inline-block; 9 | padding-top: 5px; 10 | padding-bottom: 5px; 11 | font-size: 14px; 12 | } 13 | 14 | .mat-dialog-container { 15 | background: $cdm-grey-lighter; 16 | } 17 | 18 | .button { 19 | font-weight: bold; 20 | } 21 | 22 | .delete-button { 23 | color: red; 24 | background: $white; 25 | } 26 | 27 | .cancel-button { 28 | color: $black; 29 | background: $cdm-grey-light; 30 | } 31 | -------------------------------------------------------------------------------- /UI/src/app/popups/error-popup/error-popup.component.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | warning 4 |
{{title}}
5 |

6 | 7 | close 8 | 9 |

{{message}}

10 | 11 |
12 | 17 |
18 |
19 | -------------------------------------------------------------------------------- /UI/src/app/popups/help-popup/help-popup.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { MatDialogRef } from '@angular/material/dialog'; 3 | import { appVersion, SUPPORT_EMAIL } from '@app/app.constants'; 4 | 5 | @Component({ 6 | selector: 'app-help-popup', 7 | templateUrl: './help-popup.component.html', 8 | styleUrls: ['./help-popup.component.scss'] 9 | }) 10 | export class HelpPopupComponent { 11 | 12 | version = appVersion 13 | email = SUPPORT_EMAIL 14 | emailHref = `mailto:${SUPPORT_EMAIL}` 15 | 16 | constructor(public dialogRef: MatDialogRef) { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /UI/src/app/popups/logout/logout.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Logout

4 | 5 | 6 |
7 | 8 |

You’re going to quit session in Perseus app. Are you sure?

9 | 10 | 12 |
13 | -------------------------------------------------------------------------------- /UI/src/app/popups/on-boarding/on-boarding.component.html: -------------------------------------------------------------------------------- 1 |

{{meta.title}}

2 |

{{meta.content}}

3 |
4 |
5 |
8 |
9 | {{meta.action.title}} 11 |
12 | -------------------------------------------------------------------------------- /UI/src/app/popups/open-save-dialog/open-save-dialog.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | } 4 | 5 | .error-message { 6 | margin-top: 20px !important; 7 | color: red; 8 | } 9 | -------------------------------------------------------------------------------- /UI/src/app/popups/preview-popup/preview-popup.component.html: -------------------------------------------------------------------------------- 1 |
2 |
{{ tablename }}
3 | 4 |
5 | 6 |
7 |
8 | -------------------------------------------------------------------------------- /UI/src/app/popups/preview-popup/preview-popup.component.scss: -------------------------------------------------------------------------------- 1 | .xmls { 2 | display: flex; 3 | flex-direction: column; 4 | justify-content: center; 5 | } 6 | 7 | .table-name { 8 | font-weight: 600; 9 | padding-bottom: 10px; 10 | text-transform: uppercase; 11 | } 12 | -------------------------------------------------------------------------------- /UI/src/app/popups/reset-warning/reset-warning.component.html: -------------------------------------------------------------------------------- 1 |

{{data.header}}

2 | close 4 | 5 | {{data.warning}} 6 | 7 | 9 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /UI/src/app/popups/reset-warning/reset-warning.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | } 4 | 5 | .reset-label { 6 | display: inline-block; 7 | padding-top: 5px; 8 | padding-bottom: 5px; 9 | font-size: 14px; 10 | } 11 | 12 | .reset-button { 13 | color: red; 14 | } -------------------------------------------------------------------------------- /UI/src/app/popups/reset-warning/reset-warning.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Inject } from '@angular/core'; 2 | import { MAT_DIALOG_DATA } from '@angular/material/dialog'; 3 | import { ResetWarningData } from '@models/reset-warning-data' 4 | 5 | @Component({ 6 | selector: 'app-reset-warning', 7 | templateUrl: './reset-warning.component.html', 8 | styleUrls: [ './reset-warning.component.scss', '../cdm-version-dialog/cdm-version-dialog.component.scss' ] 9 | }) 10 | export class ResetWarningComponent { 11 | constructor(@Inject(MAT_DIALOG_DATA) public data: ResetWarningData) {} 12 | } 13 | -------------------------------------------------------------------------------- /UI/src/app/popups/save-mapping-dialog/save-mapping-dialog.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | } 4 | -------------------------------------------------------------------------------- /UI/src/app/popups/select-concept-field/select-concept-field.component.html: -------------------------------------------------------------------------------- 1 |
2 | 4 | {{field}} 8 | 9 | 10 |
11 | -------------------------------------------------------------------------------- /UI/src/app/popups/select-concept-field/select-concept-field.component.scss: -------------------------------------------------------------------------------- 1 | .tables-select { 2 | background: white; 3 | overflow-y: scroll; 4 | overflow-x: scroll; 5 | width: 123px; 6 | max-height: 150px; 7 | margin: 0 10px 10px 0; 8 | } 9 | 10 | .table-select-option { 11 | height: 30px; 12 | font-size: 16px; 13 | } 14 | 15 | .mat-list-item.active { 16 | color: #e5e5e5; 17 | } 18 | -------------------------------------------------------------------------------- /UI/src/app/popups/transformation-type/transformation-type.component.html: -------------------------------------------------------------------------------- 1 |
2 | 8 | {{typeName}} 11 | 13 |
14 | -------------------------------------------------------------------------------- /UI/src/app/popups/warning-popup/warning-popup.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Inject } from '@angular/core'; 2 | import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; 3 | 4 | @Component({ 5 | selector: 'app-warning-popup', 6 | templateUrl: './warning-popup.component.html', 7 | styleUrls: ['./warning-popup.component.scss'] 8 | }) 9 | export class WarningPopupComponent { 10 | 11 | constructor(@Inject(MAT_DIALOG_DATA) public data: {header: string, message: string}, 12 | public dialogRef: MatDialogRef) { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/auxiliary/progress-console-wrapper/console-wrapper.component.scss: -------------------------------------------------------------------------------- 1 | .console-wrapper { 2 | width: 100%; 3 | 4 | display: flex; 5 | flex-direction: column; 6 | align-items: center; 7 | 8 | &__action { 9 | display: flex; 10 | justify-content: center; 11 | margin-top: 35px; 12 | 13 | height: 33px; 14 | 15 | * { 16 | margin-right: 25px; 17 | } 18 | 19 | &-abort { 20 | width: 130px; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/auxiliary/progress-console/progress-console.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Scanning... Estimated time depends on selected database

4 | 5 |
6 | 7 |
8 |

Console

9 |
10 |

{{log.message}}

11 |
12 |
13 |
14 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/cdm-dialog/cdm-console-wrapper/cdm-console-wrapper.component.scss: -------------------------------------------------------------------------------- 1 | .console-wrapper { 2 | &__action { 3 | width: 340px; 4 | 5 | button { 6 | margin: 0 auto; 7 | } 8 | 9 | &-back { 10 | width: 70px; 11 | } 12 | 13 | &-dqd { 14 | width: 150px; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/cdm-dialog/cdm-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .scan-dialog { 2 | padding: 42px 33px 35px 38px; 3 | 4 | &__header { 5 | margin-bottom: 21px; 6 | } 7 | 8 | &__title { 9 | width: 100%; 10 | position: relative; 11 | } 12 | 13 | &__icon-wrapper { 14 | display: flex; 15 | } 16 | 17 | &__icon { 18 | margin-left: 5px; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/cdm-dialog/cdm-form/cdm-destination-form/cdm-destination-form.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/UI/src/app/scan-data/cdm-dialog/cdm-form/cdm-destination-form/cdm-destination-form.component.scss -------------------------------------------------------------------------------- /UI/src/app/scan-data/cdm-dialog/cdm-form/cdm-fake-data-form/cdm-fake-data-form.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |
6 | 7 |
8 | 9 | 10 |
11 |
12 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/cdm-dialog/cdm-form/cdm-fake-data-form/cdm-fake-data-form.component.scss: -------------------------------------------------------------------------------- 1 | .checkbox { 2 | display: flex; 3 | align-items: center; 4 | margin: 22px 9px; 5 | } 6 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/cdm-dialog/cdm-form/cdm-source-form/cdm-source-form.component.scss: -------------------------------------------------------------------------------- 1 | .fake-data { 2 | display: flex; 3 | justify-content: center; 4 | height: 54px; 5 | 6 | button { 7 | width: 140px; 8 | height: 33px; 9 | background: #F9F9F9; 10 | box-shadow: 0 0 2px rgba(0, 0, 0, 0.25); 11 | border-radius: 2px; 12 | 13 | font-weight: 500; 14 | font-size: 14px; 15 | line-height: 18px; 16 | text-align: center; 17 | color: #066BBB; 18 | 19 | &:hover { 20 | background: #EBEBEB; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/code-mapping-dialog/code-mapping-console-wrapper/code-mapping-console-wrapper.component.scss: -------------------------------------------------------------------------------- 1 | .console-wrapper__action { 2 | button { 3 | width: 80px; 4 | 5 | &.back { 6 | margin-right: 20px; 7 | } 8 | 9 | &.abort { 10 | width: 130px; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/code-mapping-dialog/code-mapping-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .scan-dialog { 2 | padding: 41px 35px 35px; 3 | 4 | &__header { 5 | margin-bottom: 21px; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/conversion-dialog-status.ts: -------------------------------------------------------------------------------- 1 | export enum ConversionDialogStatus { 2 | SET_PARAMETERS = 0, 3 | CONVERSION = 1 4 | } 5 | 6 | export enum AdditionalStatusesForCdmBuilderDialog { 7 | FAKE_DATA_GENERATION = 2, 8 | DATA_QUALITY_CHECK = 3 9 | } 10 | 11 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/dqd-dialog/dqd-console-wrapper/dqd-console-wrapper.component.scss: -------------------------------------------------------------------------------- 1 | .console-wrapper__action { 2 | width: 400px; 3 | display: flex; 4 | justify-content: space-between; 5 | 6 | .confirm { 7 | width: 100px; 8 | } 9 | 10 | .cancel { 11 | width: 80px; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/dqd-dialog/dqd-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .scan-dialog { 2 | padding: 42px 29px 38px 29px; 3 | 4 | &__header { 5 | margin-bottom: 21px; 6 | margin-left: 9px; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/fake-data-dialog/fake-console-wrapper/fake-console-wrapper.component.scss: -------------------------------------------------------------------------------- 1 | .console-wrapper { 2 | &__action { 3 | width: 200px; 4 | 5 | button { 6 | margin: 0 auto; 7 | } 8 | 9 | &-back { 10 | width: 70px; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/fake-data-dialog/fake-data-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .scan-dialog { 2 | padding: 42px 35px 35px 38px; 3 | 4 | &__header { 5 | margin-bottom: 18px; 6 | 7 | &-cancel { 8 | width: 80px; 9 | background: #E5E5E5; 10 | color: #404040; 11 | margin-right: 15px; 12 | } 13 | 14 | &-scan { 15 | background: #066BBB; 16 | width: 129px; 17 | color: #FFFFFF; 18 | 19 | &:disabled { 20 | opacity: 0.5; 21 | } 22 | } 23 | } 24 | 25 | &__content { 26 | min-width: 180px; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/scan-data-dialog/scan-console-wrapper/scan-console-wrapper.component.scss: -------------------------------------------------------------------------------- 1 | .console-wrapper { 2 | &__action { 3 | &-back { 4 | width: 80px; 5 | } 6 | 7 | &-close { 8 | width: 80px; 9 | } 10 | 11 | &-save, &-link { 12 | width: 120px; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/scan-data-dialog/scan-data-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .scan-dialog { 2 | padding: 42px 33px 35px 38px; 3 | height: 100%; 4 | 5 | &__header { 6 | margin-bottom: 21px; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/scan-data-dialog/scan-data-form/scan-data-form.component.scss: -------------------------------------------------------------------------------- 1 | .scan-data-form { 2 | width: 629px; 3 | 4 | &__content { 5 | display: flex; 6 | justify-content: space-between; 7 | } 8 | 9 | &__action { 10 | display: flex; 11 | justify-content: center; 12 | margin-top: 35px; 13 | 14 | height: 33px; 15 | 16 | &-cancel { 17 | width: 80px; 18 | margin-right: 15px; 19 | } 20 | 21 | &-scan { 22 | width: 129px; 23 | 24 | &:disabled { 25 | opacity: 0.5; 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/scan-data-dialog/scan-data-form/tables-to-scan/table-to-scan/table-to-scan.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |

{{tableName}}

6 |
7 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/scan-data-dialog/scan-data-form/tables-to-scan/table-to-scan/table-to-scan.component.scss: -------------------------------------------------------------------------------- 1 | .scan-tables-content__list-item { 2 | display: flex; 3 | margin-bottom: 10px; 4 | 5 | p { 6 | font-size: 14px; 7 | line-height: 14px; 8 | 9 | color: #404040; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/styles/_variables.scss: -------------------------------------------------------------------------------- 1 | $form-height: 540px; 2 | $table-to-scan-height: 415px; 3 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/styles/file-input.scss: -------------------------------------------------------------------------------- 1 | .file-input { 2 | display: flex; 3 | 4 | input::-webkit-file-upload-button { 5 | visibility: hidden; 6 | } 7 | 8 | input { 9 | flex: 1; 10 | cursor: pointer; 11 | color: transparent; 12 | } 13 | 14 | &__text { 15 | display: flex; 16 | align-items: center; 17 | flex-basis: 0; 18 | white-space: nowrap; 19 | width: 0; 20 | z-index: 1001; 21 | 22 | font-weight: normal; 23 | font-size: 14px; 24 | line-height: 14px; 25 | color: #404040; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/styles/scan-data-buttons.scss: -------------------------------------------------------------------------------- 1 | @import "mixins"; 2 | 3 | button { 4 | @include cdm-button(); 5 | 6 | &.confirm { 7 | background: #066BBB; 8 | color: #FFFFFF; 9 | 10 | &:disabled { 11 | cursor: default; 12 | opacity: .5; 13 | } 14 | } 15 | 16 | &.cancel { 17 | background: #E5E5E5; 18 | color: #404040; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/styles/scan-data-connect-form.scss: -------------------------------------------------------------------------------- 1 | @import "mixins"; 2 | 3 | .scan-data-connect-form-control { 4 | display: flex; 5 | flex-direction: column; 6 | 7 | margin: 15px 9px; 8 | 9 | input, .mat-select { 10 | background: #F9F9F9; 11 | 12 | @include invalid-text-decoration(); 13 | } 14 | } 15 | 16 | form { 17 | a { 18 | margin-left: 10px; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/styles/scan-data-form.scss: -------------------------------------------------------------------------------- 1 | @import "mixins"; 2 | 3 | .scan-data-form-control { 4 | @include perseus-control() 5 | } 6 | -------------------------------------------------------------------------------- /UI/src/app/scan-data/styles/scan-data-normalize.scss: -------------------------------------------------------------------------------- 1 | h5 { 2 | margin: 0; 3 | } 4 | 5 | h4 { 6 | margin: 0; 7 | } 8 | 9 | p { 10 | margin: 0; 11 | } 12 | -------------------------------------------------------------------------------- /UI/src/app/server-error/server-error-icon/server-error-icon.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /UI/src/app/server-error/server-error-icon/server-error-icon.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | width: 22px; 3 | height: 17px; 4 | cursor: pointer; 5 | display: flex; 6 | justify-content: center; 7 | align-items: center; 8 | } 9 | -------------------------------------------------------------------------------- /UI/src/app/server-error/server-error-icon/server-error-icon.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-server-error-icon', 5 | templateUrl: './server-error-icon.component.html', 6 | styleUrls: ['./server-error-icon.component.scss'] 7 | }) 8 | export class ServerErrorIconComponent { 9 | } 10 | -------------------------------------------------------------------------------- /UI/src/app/server-error/server-error-popup/server-error-popup.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
5 | 6 | Server Error 7 |
8 | 9 |

Server error occurred. Please contact our support: 10 | 11 | {{email}} 12 | 13 |

14 | 15 | 16 |
17 | -------------------------------------------------------------------------------- /UI/src/app/services/auth/auth-state.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | /* 4 | * Store reset password token, 5 | * Already registered email, 6 | * Expired Link type. 7 | */ 8 | @Injectable() 9 | export class AuthStateService { 10 | private authState: any 11 | 12 | get state(): string { 13 | return this.authState 14 | } 15 | 16 | set state(state: string) { 17 | this.authState = state 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /UI/src/app/services/breadcrumb/can-redirect.service.ts: -------------------------------------------------------------------------------- 1 | export abstract class CanRedirectService { 2 | 3 | abstract breadcrumbLabel(): string 4 | 5 | abstract canRedirect(): boolean 6 | } 7 | -------------------------------------------------------------------------------- /UI/src/app/services/cdm-builder/cdm-buttons-state.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable({ 4 | providedIn: 'root' 5 | }) 6 | export class CdmButtonsStateService { 7 | testSourceConnection = false 8 | testTargetConnection = false 9 | converting = false 10 | generatingFakeData = false 11 | dqdRunning = false 12 | } 13 | -------------------------------------------------------------------------------- /UI/src/app/services/overlay/overlay-config-options.interface.ts: -------------------------------------------------------------------------------- 1 | export interface OverlayConfigOptions { 2 | disableClose?: boolean; 3 | panelClass?: string; 4 | hasBackdrop?: boolean; 5 | backdropClass?: string; 6 | positionStrategyFor?: string; 7 | payload?: any; 8 | } 9 | -------------------------------------------------------------------------------- /UI/src/app/services/overlay/overlay-dialog-data.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken } from '@angular/core'; 2 | 3 | export const OVERLAY_DIALOG_DATA = new InjectionToken('OVERLAY_DIALOG_DATA'); 4 | -------------------------------------------------------------------------------- /UI/src/app/services/perseus/user-schema.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http' 3 | import { Observable } from 'rxjs' 4 | import { perseusApiUrl } from '@app/app.constants' 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class UserSchemaService { 10 | 11 | constructor(private http: HttpClient) { } 12 | 13 | getUserSchema(): Observable { 14 | return this.http.get(`${perseusApiUrl}/get_user_schema_name`) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /UI/src/app/services/report/comments-for-report.ts: -------------------------------------------------------------------------------- 1 | import { IComment } from '@models/comment'; 2 | 3 | export function commentsForReport(comments: IComment[]): string { 4 | if (!comments || comments.length === 0) { 5 | return '' 6 | } 7 | return comments[0].text 8 | } 9 | -------------------------------------------------------------------------------- /UI/src/app/services/report/image/mapping-image.ts: -------------------------------------------------------------------------------- 1 | export interface MappingImage { 2 | height: number; 3 | width: number; 4 | base64: string; 5 | } 6 | 7 | export interface MappingForImage { 8 | source: string; 9 | target: string; 10 | } 11 | 12 | export interface MappingImageStyles { 13 | width: number; 14 | 15 | fieldWidth: number; 16 | fieldHeight: number; 17 | distanceBetweenSourceAndTarget: number; 18 | 19 | marginLeft: number; 20 | marginBottom: number; 21 | textMarginTop: number; 22 | fieldsMarginTop: number; 23 | 24 | headerFont: string; 25 | fieldFont: string; 26 | } 27 | -------------------------------------------------------------------------------- /UI/src/app/services/report/sql-keywords.ts: -------------------------------------------------------------------------------- 1 | // tslint:disable-next-line:max-line-length 2 | const sqlKeyWordsAsString = 'alter and as asc between by count create delete desc distinct drop from group having in insert into is join like not on or order select set table union update values where limit'; 3 | 4 | export const sqlKeyWords = sqlKeyWordsAsString 5 | .toLowerCase() 6 | .split(' '); 7 | 8 | export const singleQuote = '\''; 9 | export const doubleQuote = '"'; 10 | -------------------------------------------------------------------------------- /UI/src/app/services/state/state.service.ts: -------------------------------------------------------------------------------- 1 | export abstract class StateService { 2 | abstract reset(): void 3 | } 4 | -------------------------------------------------------------------------------- /UI/src/app/services/validation.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { ValidationService } from '@services/validation.service'; 2 | 3 | describe('ValidationService', () => { 4 | it('should validate Time', () => { 5 | const time = '12:10:01' 6 | const notTime = 'test' 7 | const service = new ValidationService() 8 | 9 | expect(service.validateInput('time', time)).toBe('') 10 | expect(service.validateInput('time', notTime)).toBe('Format must be HH:MM:SS') 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /UI/src/app/shared/base/base.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnDestroy } from '@angular/core'; 2 | import { ReplaySubject } from 'rxjs'; 3 | 4 | @Component({ 5 | template: '' 6 | }) 7 | export abstract class BaseComponent implements OnDestroy { 8 | 9 | private destroy$: ReplaySubject = new ReplaySubject(1); 10 | 11 | get ngUnsubscribe() { 12 | return this.destroy$.asObservable(); 13 | } 14 | 15 | ngOnDestroy(): void { 16 | this.destroy$.next(); 17 | this.destroy$.complete(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /UI/src/app/shared/cdm-checkbox/cdm-checkbox.component.html: -------------------------------------------------------------------------------- 1 |
3 | 4 | 5 | 6 |
7 | -------------------------------------------------------------------------------- /UI/src/app/shared/cdm-checkbox/cdm-checkbox.component.scss: -------------------------------------------------------------------------------- 1 | .scan-data-checkbox { 2 | width: 16px; 3 | height: 16px; 4 | margin-right: 8px; 5 | 6 | display: flex; 7 | justify-content: center; 8 | align-items: center; 9 | 10 | border: 1px solid #066BBB; 11 | box-sizing: border-box; 12 | 13 | cursor: pointer; 14 | 15 | svg { 16 | display: none; 17 | } 18 | 19 | &.selected { 20 | svg { 21 | display: block; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /UI/src/app/shared/close-dialog-button/close-dialog-button.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | width: 10px; 3 | height: 10px; 4 | cursor: pointer; 5 | display: flex; 6 | justify-content: center; 7 | align-items: center; 8 | } 9 | -------------------------------------------------------------------------------- /UI/src/app/shared/filters/filter-color-point/filter-color-point.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
6 | -------------------------------------------------------------------------------- /UI/src/app/shared/filters/filter-color-point/filter-color-point.component.scss: -------------------------------------------------------------------------------- 1 | .filter-color-point { 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | padding: 10px 0; 6 | } 7 | -------------------------------------------------------------------------------- /UI/src/app/shared/filters/filter-color-point/filter-color-point.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-filter-color-point', 5 | templateUrl: './filter-color-point.component.html', 6 | styleUrls: ['./filter-color-point.component.scss'] 7 | }) 8 | export class FilterColorPointComponent { 9 | 10 | @Input() 11 | color: string 12 | } 13 | -------------------------------------------------------------------------------- /UI/src/app/shared/filters/filter-dropdown/filter-dropdown-label/filter-dropdown-label.component.html: -------------------------------------------------------------------------------- 1 |
3 | 4 | 5 |
6 | {{name}} 7 | 8 | 9 | 10 | 11 |
12 |
13 | -------------------------------------------------------------------------------- /UI/src/app/shared/filters/filter-dropdown/filter-dropdown-label/filter-dropdown-label.component.scss: -------------------------------------------------------------------------------- 1 | .filter-dropdown-label { 2 | width: 100%; 3 | min-width: 200px; 4 | display: flex; 5 | align-items: center; 6 | padding-right: 38px; 7 | 8 | &__name { 9 | cursor: pointer; 10 | font-size: 14px; 11 | line-height: 18px; 12 | width: 100%; 13 | display: flex; 14 | justify-content: space-between; 15 | align-items: center; 16 | 17 | &.opened .section-arrow { 18 | transform: rotate(180deg); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /UI/src/app/shared/filters/filter-dropdown/filter-dropdown.component.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /UI/src/app/shared/filters/filter-dropdown/filter-dropdown.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | width: 100%; 3 | } 4 | -------------------------------------------------------------------------------- /UI/src/app/shared/filters/filter-dropdown/filter-dropdown.ts: -------------------------------------------------------------------------------- 1 | import { FilterValue } from '@models/filter/filter' 2 | 3 | export const findFilterValue = (curr: FilterValue) => (value: FilterValue) => 4 | value.filterIndex === curr.filterIndex && value.name === curr.name 5 | 6 | 7 | export const filterValues = (exclude: FilterValue) => (value: FilterValue) => 8 | value.filterIndex !== exclude.filterIndex && value.name !== exclude.name 9 | -------------------------------------------------------------------------------- /UI/src/app/shared/filters/filter-dropdown/filter-list/filter-list.component.html: -------------------------------------------------------------------------------- 1 |
2 | 5 | 6 |
7 | 8 | {{value.name}} {{toValueCount(value.count)}} 9 |
10 |
11 | -------------------------------------------------------------------------------- /UI/src/app/shared/filters/filter-dropdown/filter-list/filter-list.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../styles/mixins"; 2 | 3 | .filters-list { 4 | padding: 10px 5px 5px 36px; 5 | background-color: #fff; 6 | 7 | .filter { 8 | margin: 0 0 9px 3px; 9 | @include search-input(); 10 | 11 | &::placeholder { 12 | font-size: 12px; 13 | } 14 | } 15 | 16 | &__item { 17 | margin-bottom: 5px; 18 | display: flex; 19 | align-items: center; 20 | height: 23px; 21 | 22 | input { 23 | cursor: pointer; 24 | margin-right: 7px; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /UI/src/app/shared/hint/hint-overlay/hint-overlay.component.html: -------------------------------------------------------------------------------- 1 |
4 | {{hint.text}} 5 | 6 | See More 7 | 8 | 9 | support 10 | . 11 | 12 |
13 | -------------------------------------------------------------------------------- /UI/src/app/shared/hint/hint.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /UI/src/app/shared/hint/hint.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | :host { 4 | height: 100%; 5 | } 6 | 7 | .hint { 8 | position: relative; 9 | width: 15px; 10 | height: 100%; 11 | display: flex; 12 | justify-content: flex-end; 13 | 14 | &__icon { 15 | cursor: pointer; 16 | width: 11px; 17 | height: 11px; 18 | display: flex; 19 | justify-content: center; 20 | align-items: center; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /UI/src/app/shared/hint/warning-hint/warning-hint.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /UI/src/app/shared/hint/warning-hint/warning-hint.component.scss: -------------------------------------------------------------------------------- 1 | .hint { 2 | width: 22px; 3 | height: 17px; 4 | left: 3px; 5 | 6 | &__icon { 7 | width: 100%; 8 | height: 100%; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /UI/src/app/shared/hint/warning-hint/warning-hint.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { HintComponent } from '@shared/hint/hint.component'; 3 | 4 | @Component({ 5 | selector: 'app-warning-hint', 6 | templateUrl: './warning-hint.component.html', 7 | styleUrls: [ 8 | '../hint.component.scss', 9 | './warning-hint.component.scss' 10 | ] 11 | }) 12 | export class WarningHintComponent extends HintComponent { 13 | } 14 | -------------------------------------------------------------------------------- /UI/src/app/shared/pipes/type-to-icon.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'typeToIcon' 5 | }) 6 | export class TypeToIconPipe implements PipeTransform { 7 | 8 | transform(value: any, args?: any): any { 9 | switch (value.toLowerCase()) { 10 | case 'numeric': 11 | case 'integer': { 12 | return '“”'; 13 | } 14 | case 'date': { 15 | return 'date_range'; 16 | } 17 | default: 18 | return '#'; 19 | } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /UI/src/app/shared/pipes/typeof.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({name: 'typeofPipe'}) 4 | export class TypeofPipe implements PipeTransform { 5 | transform(value: any): string { 6 | if (typeof value !== 'boolean' && !Number.isNaN(+value)) { 7 | return 'number'; 8 | } else if (value instanceof Date || !Number.isNaN(Date.parse(value))) { 9 | return 'Date'; 10 | } else if (typeof value !== 'object' && typeof value !== 'function') { 11 | return typeof value; 12 | } 13 | return typeof value; 14 | } 15 | } -------------------------------------------------------------------------------- /UI/src/app/shared/popup/popup.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from "@angular/core"; 2 | 3 | @Component({ 4 | selector: 'app-popup', 5 | templateUrl: './popup.template.html', 6 | styleUrls: ['./popup.styles.scss'], 7 | }) 8 | export class PopupComponent { 9 | @Input() externalCssClasses: string = ''; 10 | } -------------------------------------------------------------------------------- /UI/src/app/shared/popup/popup.template.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /UI/src/app/shared/search-by-name/search-by-name.component.scss: -------------------------------------------------------------------------------- 1 | .search-by-name { 2 | display: block; 3 | } 4 | 5 | 6 | // search by name in comfy component 7 | :host(.comfy-filter-by-name) { 8 | .search-by-name { 9 | margin: 0 12px 0 8px; 10 | } 11 | } 12 | 13 | // search by name in panel component 14 | :host(.mapping-filter-by-name) { 15 | .search-by-name { 16 | margin: 0 3px 0 3px; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /UI/src/app/shared/search-input/search-input.component.scss: -------------------------------------------------------------------------------- 1 | @import "mixins"; 2 | 3 | .search-input { 4 | position: relative; 5 | 6 | svg { 7 | position: absolute; 8 | top: 50%; 9 | bottom: 50%; 10 | transform: translateY(-50%); 11 | left: 10px; 12 | } 13 | 14 | input { 15 | width: 500px; 16 | height: 30px; 17 | padding-left: 33px; 18 | @include search-input(); 19 | 20 | &::placeholder { 21 | font-weight: normal; 22 | font-size: 14px; 23 | line-height: 18px; 24 | } 25 | 26 | &:disabled { 27 | cursor: default; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /UI/src/app/shared/sql-editor/sql-editor.data.ts: -------------------------------------------------------------------------------- 1 | import { ITable } from '@models/table' 2 | import { IRow } from '@models/row' 3 | 4 | export interface SqlEditorData { 5 | table?: ITable, 6 | tables: ITable[] 7 | action: 'Create' | 'Edit' 8 | } 9 | 10 | export type AliasTableMapping = { 11 | [alias: string]: ITable 12 | } | {} 13 | 14 | export type TablesColumnsMapping = { 15 | [tableName: string]: IRow 16 | } | {} 17 | 18 | export interface TablesAliasesInfo { 19 | tablesWithoutAlias: string[] 20 | aliasTableMapping: AliasTableMapping 21 | } 22 | -------------------------------------------------------------------------------- /UI/src/app/test/test.consts.ts: -------------------------------------------------------------------------------- 1 | export const deletedArrowFields = ['canvas', 'path', 'button', 'clicked', 'sourceSVGPoint', 2 | 'targetSVGPoint', 'title', 'titleText', 'removeClickListener', 'renderer'] 3 | 4 | export const deletedRowFields = ['htmlElement'] 5 | -------------------------------------------------------------------------------- /UI/src/app/toolbar/breadcrumb/breadcrumb.component.html: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /UI/src/app/toolbar/toolbar.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { ToolbarComponent } from './toolbar.component'; 3 | import { BreadcrumbComponent } from './breadcrumb/breadcrump.component'; 4 | import { SharedModule } from '@shared/shared.module'; 5 | import { RouterModule } from '@angular/router'; 6 | 7 | @NgModule({ 8 | declarations: [ 9 | ToolbarComponent, 10 | BreadcrumbComponent 11 | ], 12 | imports: [ 13 | SharedModule, 14 | RouterModule 15 | ], 16 | exports: [ 17 | ToolbarComponent 18 | ] 19 | }) 20 | export class ToolbarModule { } 21 | -------------------------------------------------------------------------------- /UI/src/app/utils/auth-util.ts: -------------------------------------------------------------------------------- 1 | import { externalUrls } from '@app/app.constants' 2 | 3 | export const notExternalUrl = (requestUrl: string) => !externalUrls.find(url => requestUrl.includes(url)) 4 | -------------------------------------------------------------------------------- /UI/src/app/utils/blob-util.ts: -------------------------------------------------------------------------------- 1 | export function blobToObj(blob: Blob): Promise { 2 | const reader: FileReader = new FileReader(); 3 | reader.readAsText(blob); 4 | return new Promise((resolve, reject) => { 5 | reader.onloadend = () => { 6 | try { 7 | const resultAsString = reader.result as string; 8 | resolve(JSON.parse(resultAsString)); 9 | } catch (e) { 10 | reject(e); 11 | } 12 | }; 13 | reader.onerror = error => reject(error); 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /UI/src/app/utils/code-mapping-util.ts: -------------------------------------------------------------------------------- 1 | import { CodeMapping } from '@models/code-mapping/code-mapping'; 2 | 3 | export function getTerm(codeMapping: CodeMapping, sourceNameColumn) { 4 | return codeMapping.sourceCode.code[sourceNameColumn] 5 | } 6 | -------------------------------------------------------------------------------- /UI/src/app/utils/code-mirror.ts: -------------------------------------------------------------------------------- 1 | import * as CodeMirror from 'codemirror'; 2 | import { EditorConfiguration, EditorFromTextArea } from 'codemirror'; 3 | 4 | export function initCodeMirror(textEditor: HTMLTextAreaElement, 5 | config: EditorConfiguration): EditorFromTextArea { 6 | return CodeMirror.fromTextArea(textEditor, config) 7 | } 8 | -------------------------------------------------------------------------------- /UI/src/app/utils/connector.ts: -------------------------------------------------------------------------------- 1 | import { IRow } from '@models/row'; 2 | 3 | /** 4 | * @return id - arrow id for arrowCache in bridge-service 5 | */ 6 | export function getConnectorId(source: IRow, target: IRow): string { 7 | const sourceRowId = source.id; 8 | const targetRowId = target.id; 9 | const sourceTableId = source.tableId; 10 | const targetTableId = target.tableId; 11 | 12 | return `${sourceTableId}-${sourceRowId}/${targetTableId}-${targetRowId}`; 13 | } 14 | -------------------------------------------------------------------------------- /UI/src/app/utils/constant.ts: -------------------------------------------------------------------------------- 1 | import { IRow } from '@models/row'; 2 | 3 | /** 4 | * @return id - constant id for constantCache in bridge-service 5 | */ 6 | export function getConstantId(sourceTableId: number, target: IRow): string { 7 | const targetRowId = target.id; 8 | const targetTableId = target.tableId; 9 | 10 | return `${sourceTableId}/${targetTableId}-${targetRowId}`; 11 | } 12 | -------------------------------------------------------------------------------- /UI/src/app/utils/file.spec.ts: -------------------------------------------------------------------------------- 1 | import { removeExtension } from '@utils/file' 2 | 3 | describe('File util', () => { 4 | it('should remove extension from scan report', () => { 5 | const sourseName = removeExtension('mdcd_native_test.xlsx') 6 | expect(sourseName).toBe('mdcd_native_test') 7 | }) 8 | }) 9 | -------------------------------------------------------------------------------- /UI/src/app/utils/file.ts: -------------------------------------------------------------------------------- 1 | export function blobToFile(blob: Blob, name: string): File { 2 | const file: any = blob 3 | file.lastModifiedDate = new Date() 4 | file.name = name 5 | 6 | return file as File 7 | } 8 | 9 | export function removeExtension(fileName): string { 10 | if (!fileName) { 11 | return null 12 | } 13 | return fileName.slice(0, fileName.lastIndexOf('.')) 14 | } 15 | -------------------------------------------------------------------------------- /UI/src/app/utils/html-utilities.ts: -------------------------------------------------------------------------------- 1 | export function extractHtmlElement(elements: any, defaultElement: any) { 2 | return elements.length > 0 ? elements[0] : defaultElement; 3 | } 4 | -------------------------------------------------------------------------------- /UI/src/app/utils/http-headers.ts: -------------------------------------------------------------------------------- 1 | import { HttpHeaders } from '@angular/common/http'; 2 | 3 | export function createNoCacheHeaders(): HttpHeaders { 4 | return new HttpHeaders({ 5 | 'Cache-Control': 'no-cache, no-store, must-revalidate, post-check=0, pre-check=0', 6 | Pragma: 'no-cache', 7 | Expires: '0' 8 | }) 9 | } 10 | -------------------------------------------------------------------------------- /UI/src/app/utils/local.ts: -------------------------------------------------------------------------------- 1 | export function saveMappingToLocalStorage(mapping: string) { 2 | localStorage.setItem('perseus-mapping', mapping) 3 | } 4 | 5 | export function getMappingFromLocalStorage(): string { 6 | return localStorage.getItem('perseus-mapping') 7 | } 8 | -------------------------------------------------------------------------------- /UI/src/app/utils/math.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Integer division 3 | */ 4 | export function integerDivision(divisible, divisor) { 5 | const remain = divisible % divisor 6 | const result = (divisible - remain) / divisor; 7 | return remain === 0 ? result : result + 1 8 | } 9 | -------------------------------------------------------------------------------- /UI/src/app/utils/scan-data-util.ts: -------------------------------------------------------------------------------- 1 | import { dbTypeWithLimits } from '@scan-data/scan-data.constants'; 2 | 3 | export function hasLimits(type: string): string | null { 4 | const keys = Object.keys(dbTypeWithLimits) 5 | return keys.includes(type) ? dbTypeWithLimits[type] : null; 6 | } 7 | -------------------------------------------------------------------------------- /UI/src/app/utils/sort.ts: -------------------------------------------------------------------------------- 1 | export function asc(a: string, b: string) { 2 | const lowerA = a.toLowerCase() 3 | const lowerB = b.toLowerCase() 4 | 5 | if (lowerA < lowerB) { 6 | return -1 7 | } else if (lowerA > lowerB) { 8 | return 1 9 | } else { 10 | return 0 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /UI/src/app/utils/text-util.ts: -------------------------------------------------------------------------------- 1 | export function addSemicolon(str: string) { 2 | return str.slice(-1) === ';' ? str : `${str};` 3 | } 4 | -------------------------------------------------------------------------------- /UI/src/app/utils/text-width.ts: -------------------------------------------------------------------------------- 1 | export function calculateWidthByLongestWord(text: string, charWidth = 4): string { 2 | const words = text.split(' ') 3 | const longestWordLength = Math.max(...words.map(s => s.length)) * charWidth 4 | const coefficient = words.length / 3.3 // 3.3 - Magic number 5 | return `${longestWordLength * coefficient}px` 6 | } 7 | -------------------------------------------------------------------------------- /UI/src/app/vocabulary-search/chip/chip.component.html: -------------------------------------------------------------------------------- 1 |
2 | {{name}} 3 | 4 | 7 | 8 |
9 | -------------------------------------------------------------------------------- /UI/src/app/vocabulary-search/chip/chip.component.scss: -------------------------------------------------------------------------------- 1 | .vocabulary-search__chips-item { 2 | margin-bottom: 4px; 3 | border-radius: 16px; 4 | width: fit-content; 5 | padding: 8px 10px 9px 16px; 6 | display: flex; 7 | justify-content: space-between; 8 | align-items: center; 9 | font-weight: normal; 10 | font-size: 14px; 11 | line-height: 15px; 12 | color: #fff; 13 | 14 | span { 15 | padding-right: 8px; 16 | } 17 | 18 | svg { 19 | cursor: pointer; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /UI/src/app/vocabulary-search/chip/chip.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, Input, Output } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-chip', 5 | templateUrl: './chip.component.html', 6 | styleUrls: ['./chip.component.scss'] 7 | }) 8 | export class ChipComponent { 9 | 10 | @Input() 11 | id: number; 12 | 13 | @Input() 14 | name: string; 15 | 16 | @Input() 17 | backgroundColor: string; 18 | 19 | @Output() 20 | delete = new EventEmitter(); 21 | 22 | onDelete() { 23 | this.delete.emit(this.id); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /UI/src/app/vocabulary-search/vocabulary-button/vocabulary-button.component.scss: -------------------------------------------------------------------------------- 1 | .vocabulary-button { 2 | display: flex; 3 | align-items: center; 4 | justify-content: space-between; 5 | padding: 0; 6 | background-color: transparent; 7 | border: 0; 8 | box-shadow: none !important; 9 | text-align: center; 10 | color: #066BBB; 11 | width: 100px; 12 | font-weight: 500; 13 | font-size: 14px; 14 | line-height: 18px; 15 | height: 33px; 16 | outline: none; 17 | cursor: pointer; 18 | } 19 | -------------------------------------------------------------------------------- /UI/src/app/vocabulary-search/vocabulary-button/vocabulary-button.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-vocabulary-button', 5 | templateUrl: './vocabulary-button.component.html', 6 | styleUrls: ['./vocabulary-button.component.scss'] 7 | }) 8 | export class VocabularyButtonComponent { 9 | } 10 | -------------------------------------------------------------------------------- /UI/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/UI/src/assets/.gitkeep -------------------------------------------------------------------------------- /UI/src/assets/env.js: -------------------------------------------------------------------------------- 1 | (function(window) { 2 | window["envMpAYvc8QMp"] = window["env"] || {}; 3 | window["envMpAYvc8QMp"]["tenantId"] = ""; 4 | window["envMpAYvc8QMp"]["clientId"] = ""; 5 | })(this); 6 | -------------------------------------------------------------------------------- /UI/src/assets/env.template.js: -------------------------------------------------------------------------------- 1 | (function(window) { 2 | window["envMpAYvc8QMp"] = window["env"] || {}; 3 | window["envMpAYvc8QMp"]["tenantId"] = "${AZURE_TENANT_ID}"; 4 | window["envMpAYvc8QMp"]["clientId"] = "${AD_CLIENT_ID}"; 5 | })(this); 6 | -------------------------------------------------------------------------------- /UI/src/assets/icons/CDM_version.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /UI/src/assets/icons/delete.svg: -------------------------------------------------------------------------------- 1 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /UI/src/assets/icons/edit.svg: -------------------------------------------------------------------------------- 1 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /UI/src/assets/icons/error.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /UI/src/assets/icons/generate_and_save.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /UI/src/assets/icons/new_mapping.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /UI/src/assets/icons/scan_data.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /UI/src/assets/icons/three_dot_menu.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /UI/src/assets/icons/warning.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_source/cvx.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('cvx') 2 | AND lower(TARGET_VOCABULARY_ID) IN ('cvx') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_source/icd10.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('icd10') 2 | AND lower(target_vocabulary_id) IN ('icd10') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_source/icd10cm.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('icd10cm') 2 | and lower(target_vocabulary_id) in ('icd10cm') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_source/icd9cm.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('icd9cm') 2 | and lower(target_vocabulary_id) in ('icd9cm') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_source/icd9proc.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('icd9proc') 2 | AND lower(TARGET_VOCABULARY_ID) IN ('icd9proc') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_source/loinc.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('loinc') 2 | AND lower(TARGET_VOCABULARY_ID) IN ('loinc') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_source/ndc.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('ndc') 2 | AND lower(TARGET_VOCABULARY_ID) IN ('ndc') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_source/nucc.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('nucc') 2 | AND lower(TARGET_VOCABULARY_ID) IN ('nucc') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_source/procedure.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('hcpcs','cpt4', 'icd9proc','icd10pcs') 2 | AND lower(TARGET_VOCABULARY_ID) IN ('hcpcs','cpt4', 'icd9proc','icd10pcs') 3 | AND lower(TARGET_CONCEPT_CLASS_ID) NOT IN ('hcpcs modifier','cpt4 modifier','icd10pcs hierarchy') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_source/read.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) = 'read' 2 | and lower(TARGET_VOCABULARY_ID) IN ('read') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_source/revenue.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('revenue code') 2 | AND lower(target_vocabulary_id) IN ('revenue code') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_source/snomed.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('snomed') 2 | AND lower(target_vocabulary_id) IN ('snomed') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_standard/cms.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('cms place of service') 2 | AND lower(TARGET_STANDARD_CONCEPT) = 's' 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_standard/cpt4_modifier.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('cpt4') 2 | AND lower(TARGET_VOCABULARY_ID) IN ('cpt4') 3 | and lower(TARGET_CONCEPT_CLASS_ID) in ('cpt4 modifier') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_standard/cvx.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('cvx') 2 | AND (TARGET_STANDARD_CONCEPT IS NOT NULL or TARGET_STANDARD_CONCEPT != '') 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') 4 | AND lower(TARGET_STANDARD_CONCEPT) = 's' -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_standard/icd10.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('icd10') 2 | AND lower(TARGET_STANDARD_CONCEPT) = 's' 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_standard/icd10cm.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('icd10cm') 2 | AND TARGET_STANDARD_CONCEPT IS NOT NULL 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') 4 | AND lower(TARGET_STANDARD_CONCEPT) = 's' 5 | AND lower(TARGET_CONCEPT_CLASS_ID) NOT IN ('icd10cm hierarchy') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_standard/icd9cm.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('icd9cm') 2 | AND TARGET_STANDARD_CONCEPT IS NOT NULL 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') 4 | AND lower(TARGET_STANDARD_CONCEPT) = 's' -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_standard/icd9proc.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('icd9proc') 2 | AND (lower(TARGET_STANDARD_CONCEPT) = 's') 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_standard/loinc.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('loinc') 2 | AND lower(TARGET_STANDARD_CONCEPT) = 's' 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_standard/ndc.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('ndc') 2 | AND (TARGET_STANDARD_CONCEPT IS NOT NULL or TARGET_STANDARD_CONCEPT != '') 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') 4 | AND lower(TARGET_STANDARD_CONCEPT) = 's' -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_standard/nucc.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('nucc' ) 2 | AND lower(TARGET_STANDARD_CONCEPT) = 's' 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') 4 | -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_standard/procedure.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('hcpcs','cpt4', 'icd9proc','icd10pcs') 2 | AND lower(TARGET_STANDARD_CONCEPT) = 's' 3 | AND (TARGET_STANDARD_CONCEPT IS NOT NULL or TARGET_STANDARD_CONCEPT != '') 4 | AND lower(TARGET_CONCEPT_CLASS_ID) NOT IN ('hcpcs modifier','cpt4 modifier','icd10pcs hierarchy') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_standard/read.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID)='read' AND (TARGET_INVALID_REASON is NULL or TARGET_INVALID_REASON = '') 2 | AND lower(TARGET_STANDARD_CONCEPT) = 's' -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_standard/revenue.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('revenue code') 2 | AND lower(TARGET_STANDARD_CONCEPT) = 's' 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_standard/snomed.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('snomed') 2 | AND (lower(TARGET_STANDARD_CONCEPT) = 's') 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') -------------------------------------------------------------------------------- /UI/src/assets/txt/source_to_standard/ucum.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('ucum') 2 | AND lower(TARGET_VOCABULARY_ID) IN ('ucum') 3 | AND lower(TARGET_STANDARD_CONCEPT) = 's' 4 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') -------------------------------------------------------------------------------- /UI/src/environments/auth-strategies.ts: -------------------------------------------------------------------------------- 1 | export enum AuthStrategies { 2 | SMTP, // SMTP server 3 | AAD, // Azure Active Directory 4 | FAKE // Local development 5 | } 6 | -------------------------------------------------------------------------------- /UI/src/environments/concept-tables.ts: -------------------------------------------------------------------------------- 1 | export const CONCEPT_TABLES = [ 2 | 'CONCEPT', 3 | 'COMMON', 4 | 'CONDITION_OCCURRENCE', 5 | 'DEVICE_EXPOSURE', 6 | 'DRUG_EXPOSURE', 7 | 'MEASUREMENT', 8 | 'OBSERVATION', 9 | 'PROCEDURE_OCCURRENCE', 10 | 'SPECIMEN' 11 | ]; 12 | -------------------------------------------------------------------------------- /UI/src/environments/environment.azure.ts: -------------------------------------------------------------------------------- 1 | import { CONCEPT_TABLES } from './concept-tables' 2 | import { AuthStrategies } from './auth-strategies' 3 | 4 | export const environment = { 5 | production: true, 6 | serverUrl: null, 7 | conceptTables: CONCEPT_TABLES, 8 | authStrategy: AuthStrategies.AAD 9 | }; 10 | -------------------------------------------------------------------------------- /UI/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | import { CONCEPT_TABLES } from './concept-tables' 2 | import { AuthStrategies } from './auth-strategies' 3 | 4 | export const environment = { 5 | production: true, 6 | serverUrl: null, 7 | conceptTables: CONCEPT_TABLES, 8 | authStrategy: AuthStrategies.SMTP 9 | }; 10 | -------------------------------------------------------------------------------- /UI/src/favicon/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/UI/src/favicon/android-chrome-192x192.png -------------------------------------------------------------------------------- /UI/src/favicon/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/UI/src/favicon/android-chrome-512x512.png -------------------------------------------------------------------------------- /UI/src/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/UI/src/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /UI/src/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/UI/src/favicon/favicon.ico -------------------------------------------------------------------------------- /UI/src/favicon/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/UI/src/favicon/mstile-150x150.png -------------------------------------------------------------------------------- /UI/src/favicon/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /UI/src/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/UI/src/img/logo.png -------------------------------------------------------------------------------- /UI/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().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /UI/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "types": ["node"] 6 | }, 7 | "files": [ 8 | "main.ts", 9 | "polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /UI/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "test.ts", 12 | "polyfills.ts" 13 | ], 14 | "include": [ 15 | "**/*.spec.ts", 16 | "**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /UI/sshd_config: -------------------------------------------------------------------------------- 1 | Port 2222 2 | ListenAddress 0.0.0.0 3 | LoginGraceTime 180 4 | X11Forwarding yes 5 | Ciphers aes128-cbc,3des-cbc,aes256-cbc 6 | MACs hmac-sha1,hmac-sha1-96 7 | StrictModes yes 8 | SyslogFacility DAEMON 9 | PasswordAuthentication yes 10 | PermitEmptyPasswords no 11 | PermitRootLogin yes -------------------------------------------------------------------------------- /athena-api/.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | *.pyc -------------------------------------------------------------------------------- /athena-api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7 2 | ENV PYTHONDONTWRITEBYTECODE=1 3 | ENV PYTHONUNBUFFERED=1 4 | WORKDIR /app 5 | COPY requirements.txt /app/ 6 | RUN pip install -r requirements.txt 7 | COPY . /app/ 8 | 9 | RUN apt-get update \ 10 | && apt-get install -y --no-install-recommends openssh-server \ 11 | && export ROOTPASS=$(head -c 12 /dev/urandom |base64 -) && echo "root:$ROOTPASS" | chpasswd 12 | 13 | COPY sshd_config /etc/ssh/ 14 | COPY entrypoint.sh entrypoint.sh 15 | RUN chmod +x entrypoint.sh 16 | 17 | EXPOSE 5002 2222 18 | 19 | ENTRYPOINT ["./entrypoint.sh"] -------------------------------------------------------------------------------- /athena-api/app_config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from flask import Flask 4 | from utils.key_vaults import get_secrets 5 | 6 | 7 | def init_app_config(app: Flask): 8 | env = os.getenv("ATHENA_ENV").capitalize() 9 | app.config.from_object(f'config.{env}Config') 10 | if app.config["AZURE_KEY_VAULT"]: 11 | app.config.from_mapping(get_secrets()) 12 | print('App config initialized') -------------------------------------------------------------------------------- /athena-api/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | service ssh start 4 | python /app/main.py -------------------------------------------------------------------------------- /athena-api/log.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | 4 | class LevelFilter(logging.Filter): 5 | def __init__(self, max_level): 6 | self.max_level = max_level 7 | logging.Filter.__init__(self) 8 | 9 | def filter(self, record): 10 | if record.levelno <= self.max_level: 11 | return True 12 | return False 13 | -------------------------------------------------------------------------------- /athena-api/requirements.txt: -------------------------------------------------------------------------------- 1 | APScheduler==3.9.1 2 | Flask==2.0.3 3 | Flask_Cors==3.0.10 4 | pysolr==3.9.0 5 | waitress==2.1.2 6 | azure-identity==1.10.0 7 | azure-keyvault-secrets==4.4.0 8 | -------------------------------------------------------------------------------- /athena-api/sshd_config: -------------------------------------------------------------------------------- 1 | Port 2222 2 | ListenAddress 0.0.0.0 3 | LoginGraceTime 180 4 | X11Forwarding yes 5 | Ciphers aes128-cbc,3des-cbc,aes256-cbc 6 | MACs hmac-sha1,hmac-sha1-96 7 | StrictModes yes 8 | SyslogFacility DAEMON 9 | PasswordAuthentication yes 10 | PermitEmptyPasswords no 11 | PermitRootLogin yes -------------------------------------------------------------------------------- /athena-api/utils/constants.py: -------------------------------------------------------------------------------- 1 | from app import app 2 | 3 | VOCABULARY_FILTERS = { 4 | 'concept_class_id': 'conceptClass', 5 | 'domain_id': 'domain', 6 | 'invalid_reason': 'invalidReason', 7 | 'standard_concept': 'standardConcept', 8 | 'vocabulary_id': 'vocabulary', 9 | } 10 | 11 | ATHENA_CORE_NAME = 'athena' 12 | 13 | SOLR_CONN_STRING = f"{app.config['SOLR_URL']}/solr/{ATHENA_CORE_NAME}" 14 | -------------------------------------------------------------------------------- /athena-api/utils/info_response.py: -------------------------------------------------------------------------------- 1 | from flask import jsonify 2 | from config import VERSION 3 | 4 | 5 | def info_response(): 6 | return jsonify({'name': 'Athena', 'version': VERSION}) -------------------------------------------------------------------------------- /auth/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /auth/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/auth/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /auth/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar 3 | -------------------------------------------------------------------------------- /auth/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:17 as build 2 | WORKDIR /workspace/app 3 | 4 | COPY src src 5 | COPY mvnw . 6 | COPY .mvn .mvn 7 | COPY pom.xml . 8 | 9 | RUN tr -d '\015' <./mvnw >./mvnw.sh && mv ./mvnw.sh ./mvnw && chmod 770 mvnw 10 | 11 | RUN ./mvnw package 12 | 13 | FROM openjdk:17 14 | 15 | VOLUME /tmp 16 | 17 | ARG JAR_FILE=/workspace/app/target/*.jar 18 | COPY --from=build ${JAR_FILE} app.jar 19 | 20 | EXPOSE 8002 21 | 22 | ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar ${0} ${@}"] 23 | -------------------------------------------------------------------------------- /auth/src/main/java/com/softwarecountry/perseus/auth/AuthApplication.java: -------------------------------------------------------------------------------- 1 | package com.softwarecountry.perseus.auth; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class AuthApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(AuthApplication.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /auth/src/main/java/com/softwarecountry/perseus/auth/model/AppInfoResponse.java: -------------------------------------------------------------------------------- 1 | package com.softwarecountry.perseus.auth.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @Builder 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class AppInfoResponse { 13 | private Double version; 14 | private String name; 15 | } 16 | -------------------------------------------------------------------------------- /auth/src/main/java/com/softwarecountry/perseus/auth/model/User.java: -------------------------------------------------------------------------------- 1 | package com.softwarecountry.perseus.auth.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @Builder 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class User { 13 | private String username; 14 | private String email; 15 | private String firstName; 16 | private String lastName; 17 | } 18 | -------------------------------------------------------------------------------- /auth/src/main/java/com/softwarecountry/perseus/auth/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.softwarecountry.perseus.auth.service; 2 | 3 | import com.softwarecountry.perseus.auth.model.User; 4 | import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; 5 | 6 | public interface UserService { 7 | String getUsername(JwtAuthenticationToken authenticationToken); 8 | 9 | User getUser(JwtAuthenticationToken authenticationToken); 10 | } 11 | -------------------------------------------------------------------------------- /auth/src/main/java/com/softwarecountry/perseus/auth/util/EmailUtil.java: -------------------------------------------------------------------------------- 1 | package com.softwarecountry.perseus.auth.util; 2 | 3 | /** 4 | * Parse email to username. 5 | * Username can be used as DB schema name. 6 | */ 7 | public class EmailUtil { 8 | public static final int USERNAME_LIMIT = 250; 9 | 10 | public static String emailToUsername(String email) { 11 | String username = email.replace('.', '_') 12 | .replace("@", "_at_"); 13 | return username.length() > USERNAME_LIMIT ? username.substring(0, USERNAME_LIMIT) : username; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /auth/src/main/java/com/softwarecountry/perseus/auth/util/TokenAttributes.java: -------------------------------------------------------------------------------- 1 | package com.softwarecountry.perseus.auth.util; 2 | 3 | import lombok.AllArgsConstructor; 4 | 5 | import java.util.Map; 6 | 7 | @AllArgsConstructor 8 | public class TokenAttributes { 9 | private Map tokenAttributes; 10 | 11 | public static TokenAttributes of(Map tokenAttributes) { 12 | return new TokenAttributes(tokenAttributes); 13 | } 14 | 15 | public String get(String attribute) { 16 | return (String) tokenAttributes.get(attribute); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /auth/src/main/resources/application-azure.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8002 3 | error: 4 | include-message: always 5 | servlet: 6 | context-path: /auth 7 | 8 | spring: 9 | application: 10 | name: Auth 11 | cloud: 12 | azure: 13 | active-directory: 14 | enabled: true 15 | credential: 16 | client-id: ${AD_CLIENT_ID} 17 | app-id-uri: api://${AD_CLIENT_ID} 18 | -------------------------------------------------------------------------------- /auth/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8002 3 | error: 4 | include-message: always 5 | servlet: 6 | context-path: /auth 7 | 8 | spring: 9 | application: 10 | name: Auth 11 | cloud: 12 | azure: 13 | active-directory: 14 | enabled: true 15 | credential: 16 | client-id: ${AD_CLIENT_ID} 17 | app-id-uri: api://${AD_CLIENT_ID} 18 | 19 | logging: 20 | level: 21 | org: 22 | springframework: 23 | security=DEBUG: 24 | 25 | -------------------------------------------------------------------------------- /auth/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ,---. ,--. ,--. 2 | / O \ ,--.,--. ,-' '-. | ,---. 3 | | .-. | | || | '-. .-' | .-. | 4 | | | | | ' '' ' | | | | | | 5 | `--' `--' `----' `--' `--' `--' 6 | 7 | ${application.title} ${application.version} 8 | Powered by Spring Boot ${spring-boot.version} -------------------------------------------------------------------------------- /auth/src/test/java/com/softwarecountry/perseus/auth/AuthApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.softwarecountry.perseus.auth; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class AuthApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /files-manager/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /files-manager/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/files-manager/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /files-manager/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar 3 | -------------------------------------------------------------------------------- /files-manager/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | /usr/sbin/sshd -e 4 | 5 | java ${JAVA_OPTS} -jar /app.jar ${0} ${@} 6 | -------------------------------------------------------------------------------- /files-manager/src/main/java/com/arcadia/perseus/filesmanager/FilesManagerApplication.java: -------------------------------------------------------------------------------- 1 | package com.arcadia.perseus.filesmanager; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class FilesManagerApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(FilesManagerApplication.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /files-manager/src/main/java/com/arcadia/perseus/filesmanager/repository/BlobDataRepository.java: -------------------------------------------------------------------------------- 1 | package com.arcadia.perseus.filesmanager.repository; 2 | 3 | import com.arcadia.perseus.filesmanager.model.BlobData; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface BlobDataRepository extends JpaRepository { 7 | } 8 | -------------------------------------------------------------------------------- /files-manager/src/main/java/com/arcadia/perseus/filesmanager/repository/UserDataRepository.java: -------------------------------------------------------------------------------- 1 | package com.arcadia.perseus.filesmanager.repository; 2 | 3 | import com.arcadia.perseus.filesmanager.model.UserData; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.Optional; 7 | 8 | public interface UserDataRepository extends JpaRepository { 9 | Optional findFirstByHash(String hash); 10 | 11 | Optional findByHashAndUsernameAndDataKeyAndFileName(String hash, String username, String dataKey, String fileName); 12 | } 13 | -------------------------------------------------------------------------------- /files-manager/src/main/java/com/arcadia/perseus/filesmanager/service/HashService.java: -------------------------------------------------------------------------------- 1 | package com.arcadia.perseus.filesmanager.service; 2 | 3 | public interface HashService { 4 | String hash(byte[] data); 5 | } 6 | -------------------------------------------------------------------------------- /files-manager/src/main/java/com/arcadia/perseus/filesmanager/web/controller/response/InfoResponse.java: -------------------------------------------------------------------------------- 1 | package com.arcadia.perseus.filesmanager.web.controller.response; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @Builder 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class InfoResponse { 13 | private Double version; 14 | private String name; 15 | } 16 | -------------------------------------------------------------------------------- /files-manager/src/test/java/com/arcadia/perseus/filesmanager/FilesManagerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.arcadia.perseus.filesmanager; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class FilesManagerApplicationTests { 8 | 9 | @Test 10 | void contextLoads() {} 11 | } 12 | -------------------------------------------------------------------------------- /files-manager/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | driver-class-name: org.h2.Driver 4 | url: jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 5 | username: sa 6 | password: sa 7 | jpa: 8 | show-sql: false -------------------------------------------------------------------------------- /files-manager/src/test/resources/cprd_1k.etl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/files-manager/src/test/resources/cprd_1k.etl -------------------------------------------------------------------------------- /files-manager/src/test/resources/mdcd_native_test.etl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/files-manager/src/test/resources/mdcd_native_test.etl -------------------------------------------------------------------------------- /files-manager/sshd_config: -------------------------------------------------------------------------------- 1 | Port 2222 2 | ListenAddress 0.0.0.0 3 | LoginGraceTime 180 4 | X11Forwarding yes 5 | Ciphers aes128-cbc,3des-cbc,aes256-cbc 6 | MACs hmac-sha1,hmac-sha1-96 7 | StrictModes yes 8 | SyslogFacility DAEMON 9 | PasswordAuthentication yes 10 | PermitEmptyPasswords no 11 | PermitRootLogin yes -------------------------------------------------------------------------------- /images/DQD.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/DQD.gif -------------------------------------------------------------------------------- /images/FakeData.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/FakeData.gif -------------------------------------------------------------------------------- /images/LinkFieldsClone.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkFieldsClone.gif -------------------------------------------------------------------------------- /images/LinkFieldsConcept.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkFieldsConcept.gif -------------------------------------------------------------------------------- /images/LinkFieldsCondition.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkFieldsCondition.gif -------------------------------------------------------------------------------- /images/LinkFieldsConst.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkFieldsConst.gif -------------------------------------------------------------------------------- /images/LinkFieldsDirect.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkFieldsDirect.gif -------------------------------------------------------------------------------- /images/LinkFieldsGroups.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkFieldsGroups.gif -------------------------------------------------------------------------------- /images/LinkFieldsLookup.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkFieldsLookup.gif -------------------------------------------------------------------------------- /images/LinkFieldsLookup2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkFieldsLookup2.gif -------------------------------------------------------------------------------- /images/LinkFieldsMix.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkFieldsMix.gif -------------------------------------------------------------------------------- /images/LinkFieldsSimilar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkFieldsSimilar.gif -------------------------------------------------------------------------------- /images/LinkFieldsSql.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkFieldsSql.gif -------------------------------------------------------------------------------- /images/LinkFieldsSqlManual.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkFieldsSqlManual.gif -------------------------------------------------------------------------------- /images/LinkFieldsSqlVisual.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkFieldsSqlVisual.gif -------------------------------------------------------------------------------- /images/LinkFieldsStart.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkFieldsStart.gif -------------------------------------------------------------------------------- /images/LinkTables.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkTables.gif -------------------------------------------------------------------------------- /images/LinkTablesDrop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkTablesDrop.gif -------------------------------------------------------------------------------- /images/LinkTablesOrderFilter.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkTablesOrderFilter.gif -------------------------------------------------------------------------------- /images/LinkTablesSourceFields.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkTablesSourceFields.gif -------------------------------------------------------------------------------- /images/LinkTablesView.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/LinkTablesView.gif -------------------------------------------------------------------------------- /images/OpenReport.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/OpenReport.gif -------------------------------------------------------------------------------- /images/SaveOpen.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/SaveOpen.gif -------------------------------------------------------------------------------- /images/ScanData.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/ScanData.gif -------------------------------------------------------------------------------- /images/ScanSettings.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/ScanSettings.PNG -------------------------------------------------------------------------------- /images/Vocabulary.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/Vocabulary.gif -------------------------------------------------------------------------------- /images/concept.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/concept.PNG -------------------------------------------------------------------------------- /images/concept1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/concept1.PNG -------------------------------------------------------------------------------- /images/convertToCdm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/convertToCdm.gif -------------------------------------------------------------------------------- /images/etldoc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/etldoc.gif -------------------------------------------------------------------------------- /images/link_fields.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/link_fields.PNG -------------------------------------------------------------------------------- /images/link_tables.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/link_tables.PNG -------------------------------------------------------------------------------- /images/link_tables2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/link_tables2.PNG -------------------------------------------------------------------------------- /images/lookup.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/lookup.PNG -------------------------------------------------------------------------------- /images/lookup1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/lookup1.PNG -------------------------------------------------------------------------------- /images/start.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/start.PNG -------------------------------------------------------------------------------- /images/start1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/start1.PNG -------------------------------------------------------------------------------- /images/usagi.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/usagi.PNG -------------------------------------------------------------------------------- /images/usagi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/usagi.gif -------------------------------------------------------------------------------- /images/usagi1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/usagi1.PNG -------------------------------------------------------------------------------- /images/usagi2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/usagi2.gif -------------------------------------------------------------------------------- /images/usagi3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/usagi3.gif -------------------------------------------------------------------------------- /images/usagi4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/usagi4.gif -------------------------------------------------------------------------------- /images/usagi5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/usagi5.gif -------------------------------------------------------------------------------- /images/usagi6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/images/usagi6.gif -------------------------------------------------------------------------------- /nginx/default.conf.template: -------------------------------------------------------------------------------- 1 | client_max_body_size 100m; 2 | 3 | proxy_cache_path /var/cache/nginx/tokens levels=1 keys_zone=token_responses:1m max_size=10m; 4 | 5 | include /etc/nginx/server.${NGINX_ENV}.conf; 6 | -------------------------------------------------------------------------------- /nginx/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | set -eu 3 | 4 | envsubst '${NGINX_ENV}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf 5 | 6 | service ssh start 7 | 8 | exec nginx -g 'daemon off;' 9 | -------------------------------------------------------------------------------- /nginx/server.init.conf: -------------------------------------------------------------------------------- 1 | server { 2 | 3 | listen 80; 4 | listen [::]:80; 5 | server_name perseus.softwarecountry.com; 6 | 7 | location /.well-known/acme-challenge/ { 8 | root /verify; 9 | default_type "text/plain"; 10 | } 11 | 12 | location = /.well-known/acme-challenge/ { 13 | return 404; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /nginx/sshd_config: -------------------------------------------------------------------------------- 1 | Port 2222 2 | ListenAddress 0.0.0.0 3 | LoginGraceTime 180 4 | X11Forwarding yes 5 | Ciphers aes128-cbc,3des-cbc,aes256-cbc 6 | MACs hmac-sha1,hmac-sha1-96 7 | StrictModes yes 8 | SyslogFacility DAEMON 9 | PasswordAuthentication yes 10 | PermitEmptyPasswords no 11 | PermitRootLogin yes -------------------------------------------------------------------------------- /perseus-api/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | 3 | cache 4 | 5 | test/resource/to_extract 6 | 7 | model/generate -------------------------------------------------------------------------------- /perseus-api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7 2 | ENV PYTHONDONTWRITEBYTECODE=1 3 | ENV PYTHONUNBUFFERED=1 4 | WORKDIR /app 5 | COPY requirements.txt /app/ 6 | RUN pip install -r requirements.txt 7 | COPY . /app/ 8 | 9 | RUN apt-get update \ 10 | && apt-get install -y --no-install-recommends openssh-server \ 11 | && export ROOTPASS=$(head -c 12 /dev/urandom |base64 -) && echo "root:$ROOTPASS" | chpasswd 12 | 13 | COPY sshd_config /etc/ssh/ 14 | 15 | COPY entrypoint.sh entrypoint.sh 16 | RUN chmod +x entrypoint.sh 17 | 18 | EXPOSE 5000 2222 19 | 20 | ENTRYPOINT ["./entrypoint.sh"] -------------------------------------------------------------------------------- /perseus-api/app_config.py: -------------------------------------------------------------------------------- 1 | import os 2 | from flask import Flask 3 | from utils.key_vaults import get_secrets 4 | 5 | 6 | def init_app_config(app: Flask): 7 | env = os.getenv("PERSEUS_ENV").capitalize() 8 | app.config.from_object(f'config.{env}Config') 9 | if app.config["AZURE_KEY_VAULT"]: 10 | app.config.from_mapping(get_secrets()) 11 | print('App config initialized') -------------------------------------------------------------------------------- /perseus-api/create_tables.py: -------------------------------------------------------------------------------- 1 | from db import app_logic_db 2 | from model.etl_mapping import EtlMapping 3 | from model.user_defined_lookup import UserDefinedLookup 4 | 5 | 6 | def create_tables(): 7 | app_logic_db.create_tables([EtlMapping, UserDefinedLookup]) 8 | -------------------------------------------------------------------------------- /perseus-api/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | service ssh start 4 | python /app/main.py -------------------------------------------------------------------------------- /perseus-api/flow.md: -------------------------------------------------------------------------------- 1 | 1. Open main page 2 | - Provided cdm versions 3 | 2. Load scan report: 4 | - Created Source DB schema, store scan-report file on server at user folder 5 | 3. Set CDM Version 6 | 4. Create Mapping 7 | 5. User create lookup 8 | - Server store lookup at user directory -------------------------------------------------------------------------------- /perseus-api/log.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | 4 | class LevelFilter(logging.Filter): 5 | def __init__(self, max_level): 6 | self.max_level = max_level 7 | logging.Filter.__init__(self) 8 | 9 | def filter(self, record): 10 | if record.levelno <= self.max_level: 11 | return True 12 | return False 13 | -------------------------------------------------------------------------------- /perseus-api/model/Batch.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT ENROLID AS person_id, ENROLID AS person_source 2 | FROM {sc}.ENROLLMENT_DETAIL 3 | ORDER BY 1 -------------------------------------------------------------------------------- /perseus-api/model/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/perseus-api/model/__init__.py -------------------------------------------------------------------------------- /perseus-api/model/base_model.py: -------------------------------------------------------------------------------- 1 | from peewee import Model 2 | 3 | from db import app_logic_db 4 | 5 | 6 | class BaseModel(Model): 7 | class Meta: 8 | database = app_logic_db 9 | schema = 'perseus' 10 | -------------------------------------------------------------------------------- /perseus-api/model/etl_mapping.py: -------------------------------------------------------------------------------- 1 | from peewee import AutoField, CharField, BigIntegerField 2 | 3 | from model.base_model import BaseModel 4 | 5 | 6 | class EtlMapping(BaseModel): 7 | id = AutoField() 8 | username = CharField() 9 | user_schema_name = CharField() 10 | source_schema_name = CharField(null=True) 11 | cdm_version = CharField(null=True) 12 | scan_report_name = CharField(null=True) 13 | scan_report_id = BigIntegerField(null=True) 14 | 15 | class Meta: 16 | db_table = 'etl_mappings' 17 | -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_source/cvx.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('cvx') 2 | AND lower(TARGET_VOCABULARY_ID) IN ('cvx') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_source/icd10.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('icd10') 2 | AND lower(target_vocabulary_id) IN ('icd10') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_source/icd10cm.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('icd10cm') 2 | and lower(target_vocabulary_id) in ('icd10cm') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_source/icd9cm.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('icd9cm') 2 | and lower(target_vocabulary_id) in ('icd9cm') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_source/icd9proc.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('icd9proc') 2 | AND lower(TARGET_VOCABULARY_ID) IN ('icd9proc') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_source/loinc.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('loinc') 2 | AND lower(TARGET_VOCABULARY_ID) IN ('loinc') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_source/ndc.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('ndc') 2 | AND lower(TARGET_VOCABULARY_ID) IN ('ndc') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_source/nucc.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('nucc') 2 | AND lower(TARGET_VOCABULARY_ID) IN ('nucc') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_source/procedure.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('hcpcs','cpt4', 'icd9proc','icd10pcs') 2 | AND lower(TARGET_VOCABULARY_ID) IN ('hcpcs','cpt4', 'icd9proc','icd10pcs') 3 | AND lower(TARGET_CONCEPT_CLASS_ID) NOT IN ('hcpcs modifier','cpt4 modifier','icd10pcs hierarchy') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_source/read.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) = 'read' 2 | and lower(TARGET_VOCABULARY_ID) IN ('read') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_source/revenue.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('revenue code') 2 | AND lower(target_vocabulary_id) IN ('revenue code') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_source/snomed.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('snomed') 2 | AND lower(target_vocabulary_id) IN ('snomed') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_standard/cms.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('cms place of service') 2 | AND lower(TARGET_STANDARD_CONCEPT) = 's' 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_standard/cpt4_modifier.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('cpt4') 2 | AND lower(TARGET_VOCABULARY_ID) IN ('cpt4') 3 | and lower(TARGET_CONCEPT_CLASS_ID) in ('cpt4 modifier') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_standard/cvx.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('cvx') 2 | AND (TARGET_STANDARD_CONCEPT IS NOT NULL or TARGET_STANDARD_CONCEPT != '') 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') 4 | AND lower(TARGET_STANDARD_CONCEPT) = 's' -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_standard/icd10.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('icd10') 2 | AND lower(TARGET_STANDARD_CONCEPT) = 's' 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_standard/icd10cm.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('icd10cm') 2 | AND TARGET_STANDARD_CONCEPT IS NOT NULL 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') 4 | AND lower(TARGET_STANDARD_CONCEPT) = 's' 5 | AND lower(TARGET_CONCEPT_CLASS_ID) NOT IN ('icd10cm hierarchy') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_standard/icd9cm.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('icd9cm') 2 | AND TARGET_STANDARD_CONCEPT IS NOT NULL 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') 4 | AND lower(TARGET_STANDARD_CONCEPT) = 's' -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_standard/icd9proc.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('icd9proc') 2 | AND (lower(TARGET_STANDARD_CONCEPT) = 's') 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_standard/loinc.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('loinc') 2 | AND lower(TARGET_STANDARD_CONCEPT) = 's' 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_standard/ndc.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('ndc') 2 | AND (TARGET_STANDARD_CONCEPT IS NOT NULL or TARGET_STANDARD_CONCEPT != '') 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') 4 | AND lower(TARGET_STANDARD_CONCEPT) = 's' -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_standard/nucc.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('nucc' ) 2 | AND lower(TARGET_STANDARD_CONCEPT) = 's' 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') 4 | -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_standard/procedure.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('hcpcs','cpt4', 'icd9proc','icd10pcs') 2 | AND lower(TARGET_STANDARD_CONCEPT) = 's' 3 | AND (TARGET_STANDARD_CONCEPT IS NOT NULL or TARGET_STANDARD_CONCEPT != '') 4 | AND lower(TARGET_CONCEPT_CLASS_ID) NOT IN ('hcpcs modifier','cpt4 modifier','icd10pcs hierarchy') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_standard/read.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID)='read' AND (TARGET_INVALID_REASON is NULL or TARGET_INVALID_REASON = '') 2 | AND lower(TARGET_STANDARD_CONCEPT) = 's' -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_standard/revenue.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('revenue code') 2 | AND lower(TARGET_STANDARD_CONCEPT) = 's' 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_standard/snomed.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('snomed') 2 | AND (lower(TARGET_STANDARD_CONCEPT) = 's') 3 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') -------------------------------------------------------------------------------- /perseus-api/model/lookups/source_to_standard/ucum.txt: -------------------------------------------------------------------------------- 1 | WHERE lower(SOURCE_VOCABULARY_ID) IN ('ucum') 2 | AND lower(TARGET_VOCABULARY_ID) IN ('ucum') 3 | AND lower(TARGET_STANDARD_CONCEPT) = 's' 4 | AND (TARGET_INVALID_REASON IS NULL or TARGET_INVALID_REASON = '') -------------------------------------------------------------------------------- /perseus-api/model/lookups/template_result_only_source_to_standard.txt: -------------------------------------------------------------------------------- 1 | {base}, 2 | Standard AS 3 | ( 4 | {source_to_standard} 5 | ) 6 | 7 | SELECT DISTINCT 8 | Standard.*, 9 | NULL AS SOURCE_VOCABULARY_ID, 10 | NULL AS SOURCE_TARGET_CONCEPT_ID, 11 | NULL AS SOURCE_VALID_START_DATE, 12 | NULL AS SOURCE_VALID_END_DATE, 13 | ingredient_level.ingredient_concept_id 14 | FROM Standard 15 | LEFT JOIN ingredient_level ON ingredient_level.concept_id=Standard.TARGET_CONCEPT_ID -------------------------------------------------------------------------------- /perseus-api/model/sources/mock_input/mock.json: -------------------------------------------------------------------------------- 1 | {"mapping_items": []} -------------------------------------------------------------------------------- /perseus-api/model/user_defined_lookup.py: -------------------------------------------------------------------------------- 1 | from peewee import CharField, TextField, AutoField 2 | from model.base_model import BaseModel 3 | 4 | 5 | class UserDefinedLookup(BaseModel): 6 | id = AutoField() 7 | name = CharField() 8 | username = CharField() 9 | source_to_standard = TextField() 10 | source_to_source = TextField() 11 | 12 | class Meta: 13 | db_table = 'user_defined_lookups' 14 | indexes = ( 15 | (('name', 'username'), True), 16 | ) 17 | -------------------------------------------------------------------------------- /perseus-api/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.0.3 2 | Flask_Cors==3.0.10 3 | pandas==0.23.4 4 | pandasql==0.7.3 5 | peewee 6 | waitress==2.1.2 7 | Werkzeug 8 | xlrd==1.2.0 9 | itsdangerous 10 | py-postgresql 11 | psycopg2-binary 12 | requests 13 | APScheduler==3.9.1 14 | azure-identity==1.10.0 15 | azure-keyvault-secrets==4.4.0 -------------------------------------------------------------------------------- /perseus-api/services/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/perseus-api/services/__init__.py -------------------------------------------------------------------------------- /perseus-api/services/model/etl_archive_content.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | 4 | @dataclass 5 | class EtlArchiveContent: 6 | scan_report_file_name: str 7 | mapping_json_file_name: str -------------------------------------------------------------------------------- /perseus-api/services/request/generate_etl_archive_request.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Any 3 | 4 | 5 | @dataclass 6 | class GenerateEtlArchiveRequest: 7 | name: str 8 | etl_mapping_id: int 9 | etl_configuration: Any 10 | 11 | 12 | def from_json(json: dict): 13 | return GenerateEtlArchiveRequest( 14 | name=json['name'], 15 | etl_mapping_id=json['etl_mapping_id'], 16 | etl_configuration=json['etl_configuration'] 17 | ) -------------------------------------------------------------------------------- /perseus-api/services/request/scan_report_request.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | 4 | @dataclass 5 | class ScanReportRequest: 6 | data_id: int 7 | file_name: str 8 | cdm_version: str or None 9 | 10 | 11 | def from_json(json: dict): 12 | return ScanReportRequest( 13 | data_id=json['dataId'], 14 | file_name=json['fileName'], 15 | cdm_version=json.get('cdmVersion') 16 | ) 17 | -------------------------------------------------------------------------------- /perseus-api/services/request/set_cdm_version_request.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | 4 | @dataclass 5 | class SetCdmVersionRequest: 6 | etl_mapping_id: int 7 | cdm_version: str 8 | 9 | 10 | def from_json(json: dict): 11 | return SetCdmVersionRequest( 12 | etl_mapping_id=json['etlMappingId'], 13 | cdm_version=json['cdmVersion'] 14 | ) -------------------------------------------------------------------------------- /perseus-api/services/response/file_save_reponse.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | 4 | @dataclass 5 | class FileSaveResponse: 6 | id: int 7 | username: str 8 | dataKey: str 9 | fileName: str 10 | 11 | 12 | def from_json(json: dict): 13 | return FileSaveResponse( 14 | id=json['id'], 15 | username=json['username'], 16 | dataKey=json['dataKey'], 17 | fileName=json['fileName'] 18 | ) 19 | -------------------------------------------------------------------------------- /perseus-api/services/response/lookup_list_item_response.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from model.user_defined_lookup import UserDefinedLookup 4 | 5 | 6 | @dataclass 7 | class LookupListItemResponse: 8 | id: int or None 9 | name: str 10 | 11 | 12 | def from_user_defined_lookup(lookup: UserDefinedLookup): 13 | return LookupListItemResponse(id=lookup.id, name=lookup.name) 14 | -------------------------------------------------------------------------------- /perseus-api/sshd_config: -------------------------------------------------------------------------------- 1 | Port 2222 2 | ListenAddress 0.0.0.0 3 | LoginGraceTime 180 4 | X11Forwarding yes 5 | Ciphers aes128-cbc,3des-cbc,aes256-cbc 6 | MACs hmac-sha1,hmac-sha1-96 7 | StrictModes yes 8 | SyslogFacility DAEMON 9 | PasswordAuthentication yes 10 | PermitEmptyPasswords no 11 | PermitRootLogin yes -------------------------------------------------------------------------------- /perseus-api/test/resource/mdcd_native_test.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/perseus-api/test/resource/mdcd_native_test.xlsx -------------------------------------------------------------------------------- /perseus-api/test/resource/test.etl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/perseus-api/test/resource/test.etl -------------------------------------------------------------------------------- /perseus-api/test/services/files_manager_service_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from services.files_manager_service import get_file 4 | from utils.exceptions import InvalidUsage 5 | 6 | 7 | class FilesManagerTest(unittest.TestCase): 8 | def test_get_file(self): 9 | data_id = 1 10 | file_resource = get_file(data_id) 11 | self.assertIsNotNone(file_resource) 12 | 13 | def test_not_found(self): 14 | data_id = 0 15 | with self.assertRaises(InvalidUsage): 16 | get_file(data_id) 17 | 18 | 19 | if __name__ == '__main__': 20 | unittest.main() 21 | -------------------------------------------------------------------------------- /perseus-api/test/utils/directory_util_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from pathlib import Path 3 | 4 | from utils import directory_util 5 | 6 | 7 | class DirectoryUtilTest(unittest.TestCase): 8 | def test_get_filenames_in_directory(self): 9 | directory = Path('../resource') 10 | filenames_in_directory = directory_util.get_filenames_in_directory(directory) 11 | print(filenames_in_directory) 12 | self.assertTrue(len(filenames_in_directory)) 13 | 14 | 15 | if __name__ == '__main__': 16 | unittest.main() -------------------------------------------------------------------------------- /perseus-api/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .constants import CDM_SCHEMA_PATH, CDM_VERSION_LIST, UPLOAD_SCAN_REPORT_FOLDER, GENERATE_ETL_XML_PATH 2 | from .exceptions import InvalidUsage 3 | 4 | __all__ = ['CDM_SCHEMA_PATH', 5 | 'CDM_VERSION_LIST', 6 | 'InvalidUsage', 7 | 'UPLOAD_SCAN_REPORT_FOLDER', 8 | 'GENERATE_ETL_XML_PATH'] 9 | -------------------------------------------------------------------------------- /perseus-api/utils/directory_util.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | 4 | 5 | def is_directory_contains_file(directory: Path or str, file_name: str): 6 | return file_name in os.listdir(directory) 7 | 8 | 9 | def get_filenames_in_directory(directory: Path): 10 | return next(os.walk(directory), (None, None, []))[2] -------------------------------------------------------------------------------- /perseus-api/utils/file_util.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | 4 | 5 | def delete_if_exist(path: str or Path): 6 | if os.path.exists(path): 7 | os.remove(path) 8 | 9 | 10 | -------------------------------------------------------------------------------- /perseus-api/utils/info_response.py: -------------------------------------------------------------------------------- 1 | from flask import jsonify 2 | 3 | from config import VERSION 4 | 5 | 6 | def info_response(): 7 | return jsonify({'name': 'Perseus', 'version': VERSION}) -------------------------------------------------------------------------------- /perseus-api/utils/string_util.py: -------------------------------------------------------------------------------- 1 | def hasCapitalLetter(string: str) -> bool: 2 | return string != string.lower() -------------------------------------------------------------------------------- /perseus-api/utils/username_header.py: -------------------------------------------------------------------------------- 1 | from flask import request 2 | from functools import wraps 3 | from utils import InvalidUsage 4 | 5 | 6 | def username_header(f): 7 | @wraps(f) 8 | def decorator(*args, **kwargs): 9 | current_user = request.headers.get('Username') 10 | if current_user is None: 11 | raise InvalidUsage('Username header not present') 12 | return f(current_user, *args, **kwargs) 13 | 14 | return decorator 15 | -------------------------------------------------------------------------------- /perseus-api/view/__init__.py: -------------------------------------------------------------------------------- 1 | import view.Table 2 | 3 | __all__ = ['Table', ] -------------------------------------------------------------------------------- /shared-db/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres 2 | 3 | COPY init.sql /docker-entrypoint-initdb.d/ 4 | 5 | ENV POSTGRES_USER admin 6 | ENV POSTGRES_PASSWORD password 7 | ENV POSTGRES_DB shared 8 | ENV PGDATA /data/postgres 9 | 10 | EXPOSE 5432 -------------------------------------------------------------------------------- /solr/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM solr:8.8.1 2 | 3 | USER root 4 | 5 | COPY athena /opt/solr/server/solr/configsets/athena 6 | COPY usagi /opt/solr/server/solr/configsets/usagi 7 | COPY postgresql-42.2.19.jar /opt/solr/dist/postgresql-42.2.19.jar 8 | 9 | RUN apt-get update \ 10 | && apt-get install -y --no-install-recommends openssh-server \ 11 | && export ROOTPASS=$(head -c 12 /dev/urandom |base64 -) && echo "root:$ROOTPASS" | chpasswd 12 | 13 | COPY sshd_config /etc/ssh/ 14 | COPY entrypoint.sh entrypoint.sh 15 | RUN chmod +x entrypoint.sh 16 | 17 | EXPOSE 8983 2222 18 | 19 | ENTRYPOINT ["./entrypoint.sh"] -------------------------------------------------------------------------------- /solr/athena/conf/lang/contractions_ca.txt: -------------------------------------------------------------------------------- 1 | # Set of Catalan contractions for ElisionFilter 2 | # TODO: load this as a resource from the analyzer and sync it in build.xml 3 | d 4 | l 5 | m 6 | n 7 | s 8 | t 9 | -------------------------------------------------------------------------------- /solr/athena/conf/lang/contractions_fr.txt: -------------------------------------------------------------------------------- 1 | # Set of French contractions for ElisionFilter 2 | # TODO: load this as a resource from the analyzer and sync it in build.xml 3 | l 4 | m 5 | t 6 | qu 7 | n 8 | s 9 | j 10 | d 11 | c 12 | jusqu 13 | quoiqu 14 | lorsqu 15 | puisqu 16 | -------------------------------------------------------------------------------- /solr/athena/conf/lang/contractions_ga.txt: -------------------------------------------------------------------------------- 1 | # Set of Irish contractions for ElisionFilter 2 | # TODO: load this as a resource from the analyzer and sync it in build.xml 3 | d 4 | m 5 | b 6 | -------------------------------------------------------------------------------- /solr/athena/conf/lang/contractions_it.txt: -------------------------------------------------------------------------------- 1 | # Set of Italian contractions for ElisionFilter 2 | # TODO: load this as a resource from the analyzer and sync it in build.xml 3 | c 4 | l 5 | all 6 | dall 7 | dell 8 | nell 9 | sull 10 | coll 11 | pell 12 | gl 13 | agl 14 | dagl 15 | degl 16 | negl 17 | sugl 18 | un 19 | m 20 | t 21 | s 22 | v 23 | d 24 | -------------------------------------------------------------------------------- /solr/athena/conf/lang/hyphenations_ga.txt: -------------------------------------------------------------------------------- 1 | # Set of Irish hyphenations for StopFilter 2 | # TODO: load this as a resource from the analyzer and sync it in build.xml 3 | h 4 | n 5 | t 6 | -------------------------------------------------------------------------------- /solr/athena/conf/lang/stemdict_nl.txt: -------------------------------------------------------------------------------- 1 | # Set of overrides for the dutch stemmer 2 | # TODO: load this as a resource from the analyzer and sync it in build.xml 3 | fiets fiets 4 | bromfiets bromfiets 5 | ei eier 6 | kind kinder 7 | -------------------------------------------------------------------------------- /solr/athena/conf/lang/stopwords_hy.txt: -------------------------------------------------------------------------------- 1 | # example set of Armenian stopwords. 2 | այդ 3 | այլ 4 | այն 5 | այս 6 | դու 7 | դուք 8 | եմ 9 | են 10 | ենք 11 | ես 12 | եք 13 | է 14 | էի 15 | էին 16 | էինք 17 | էիր 18 | էիք 19 | էր 20 | ըստ 21 | թ 22 | ի 23 | ին 24 | իսկ 25 | իր 26 | կամ 27 | համար 28 | հետ 29 | հետո 30 | մենք 31 | մեջ 32 | մի 33 | ն 34 | նա 35 | նաև 36 | նրա 37 | նրանք 38 | որ 39 | որը 40 | որոնք 41 | որպես 42 | ու 43 | ում 44 | պիտի 45 | վրա 46 | և 47 | -------------------------------------------------------------------------------- /solr/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | service ssh start 4 | runuser -u solr -- precreate-core athena /opt/solr/server/solr/configsets/athena/conf 5 | runuser -u solr -- solr-precreate usagi /opt/solr/server/solr/configsets/usagi/conf -------------------------------------------------------------------------------- /solr/postgresql-42.2.19.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/solr/postgresql-42.2.19.jar -------------------------------------------------------------------------------- /solr/sshd_config: -------------------------------------------------------------------------------- 1 | Port 2222 2 | ListenAddress 0.0.0.0 3 | LoginGraceTime 180 4 | X11Forwarding yes 5 | Ciphers aes128-cbc,3des-cbc,aes256-cbc 6 | MACs hmac-sha1,hmac-sha1-96 7 | StrictModes yes 8 | SyslogFacility DAEMON 9 | PasswordAuthentication yes 10 | PermitEmptyPasswords no 11 | PermitRootLogin yes -------------------------------------------------------------------------------- /solr/usagi/conf/lang/contractions_ca.txt: -------------------------------------------------------------------------------- 1 | # Set of Catalan contractions for ElisionFilter 2 | # TODO: load this as a resource from the analyzer and sync it in build.xml 3 | d 4 | l 5 | m 6 | n 7 | s 8 | t 9 | -------------------------------------------------------------------------------- /solr/usagi/conf/lang/contractions_fr.txt: -------------------------------------------------------------------------------- 1 | # Set of French contractions for ElisionFilter 2 | # TODO: load this as a resource from the analyzer and sync it in build.xml 3 | l 4 | m 5 | t 6 | qu 7 | n 8 | s 9 | j 10 | d 11 | c 12 | jusqu 13 | quoiqu 14 | lorsqu 15 | puisqu 16 | -------------------------------------------------------------------------------- /solr/usagi/conf/lang/contractions_ga.txt: -------------------------------------------------------------------------------- 1 | # Set of Irish contractions for ElisionFilter 2 | # TODO: load this as a resource from the analyzer and sync it in build.xml 3 | d 4 | m 5 | b 6 | -------------------------------------------------------------------------------- /solr/usagi/conf/lang/contractions_it.txt: -------------------------------------------------------------------------------- 1 | # Set of Italian contractions for ElisionFilter 2 | # TODO: load this as a resource from the analyzer and sync it in build.xml 3 | c 4 | l 5 | all 6 | dall 7 | dell 8 | nell 9 | sull 10 | coll 11 | pell 12 | gl 13 | agl 14 | dagl 15 | degl 16 | negl 17 | sugl 18 | un 19 | m 20 | t 21 | s 22 | v 23 | d 24 | -------------------------------------------------------------------------------- /solr/usagi/conf/lang/hyphenations_ga.txt: -------------------------------------------------------------------------------- 1 | # Set of Irish hyphenations for StopFilter 2 | # TODO: load this as a resource from the analyzer and sync it in build.xml 3 | h 4 | n 5 | t 6 | -------------------------------------------------------------------------------- /solr/usagi/conf/lang/stemdict_nl.txt: -------------------------------------------------------------------------------- 1 | # Set of overrides for the dutch stemmer 2 | # TODO: load this as a resource from the analyzer and sync it in build.xml 3 | fiets fiets 4 | bromfiets bromfiets 5 | ei eier 6 | kind kinder 7 | -------------------------------------------------------------------------------- /solr/usagi/conf/lang/stopwords_hy.txt: -------------------------------------------------------------------------------- 1 | # example set of Armenian stopwords. 2 | այդ 3 | այլ 4 | այն 5 | այս 6 | դու 7 | դուք 8 | եմ 9 | են 10 | ենք 11 | ես 12 | եք 13 | է 14 | էի 15 | էին 16 | էինք 17 | էիր 18 | էիք 19 | էր 20 | ըստ 21 | թ 22 | ի 23 | ին 24 | իսկ 25 | իր 26 | կամ 27 | համար 28 | հետ 29 | հետո 30 | մենք 31 | մեջ 32 | մի 33 | ն 34 | նա 35 | նաև 36 | նրա 37 | նրանք 38 | որ 39 | որը 40 | որոնք 41 | որպես 42 | ու 43 | ում 44 | պիտի 45 | վրա 46 | և 47 | -------------------------------------------------------------------------------- /swagger-ui/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM swaggerapi/swagger-ui 2 | 3 | ENV BASE_URL=/swagger 4 | ENV URLS_PRIMARY_NAME=White-Rabbit 5 | ENV URLS="[ \ 6 | { url: 'docs/white-rabbit.yml', name: 'White-Rabbit' } \ 7 | , { url: 'docs/data-quality-dashboard.yml', name: 'Data-Quality-Dashboard' } \ 8 | , { url: 'docs/cdm-builder.yml', name: 'Cdm-Builder' } \ 9 | ]" 10 | 11 | COPY white-rabbit.yml /usr/share/nginx/html/docs/ 12 | COPY data-quality-dashboard.yml /usr/share/nginx/html/docs/ 13 | COPY cdm-builder.yml /usr/share/nginx/html/docs/ 14 | 15 | EXPOSE 8080 -------------------------------------------------------------------------------- /usagi-api/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc -------------------------------------------------------------------------------- /usagi-api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7 2 | ENV PYTHONDONTWRITEBYTECODE=1 3 | ENV PYTHONUNBUFFERED=1 4 | WORKDIR /app 5 | COPY requirements.txt /app/ 6 | RUN pip install -r requirements.txt 7 | COPY . /app/ 8 | 9 | RUN apt-get update \ 10 | && apt-get install -y --no-install-recommends openssh-server \ 11 | && export ROOTPASS=$(head -c 12 /dev/urandom |base64 -) && echo "root:$ROOTPASS" | chpasswd \ 12 | 13 | COPY sshd_config /etc/ssh/ 14 | 15 | EXPOSE 5003 16 | EXPOSE 2222 17 | 18 | ENTRYPOINT ["python", "/app/main.py"] -------------------------------------------------------------------------------- /usagi-api/app_config.py: -------------------------------------------------------------------------------- 1 | import os 2 | from flask import Flask 3 | from util.key_vaults import get_secrets 4 | 5 | 6 | def init_app_config(app: Flask): 7 | env = os.getenv("USAGI_ENV").capitalize() 8 | app.config.from_object(f'config.{env}Config') 9 | if app.config["AZURE_KEY_VAULT"]: 10 | app.config.from_mapping(get_secrets()) 11 | print('App config initialized') -------------------------------------------------------------------------------- /usagi-api/log.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | 4 | class LevelFilter(logging.Filter): 5 | def __init__(self, max_level): 6 | self.max_level = max_level 7 | logging.Filter.__init__(self) 8 | 9 | def filter(self, record): 10 | if record.levelno <= self.max_level: 11 | return True 12 | return False 13 | -------------------------------------------------------------------------------- /usagi-api/model/file_manager/file_save_reponse.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | """ 4 | Unused 5 | """ 6 | @dataclass 7 | class FileSaveResponse: 8 | id: int 9 | username: str 10 | dataKey: str 11 | fileName: str 12 | filePath: str or None 13 | 14 | 15 | def from_json(json: dict): 16 | return FileSaveResponse( 17 | id=json['id'], 18 | username=json['username'], 19 | dataKey=json['dataKey'], 20 | fileName=json['fileName'], 21 | filePath=None 22 | ) 23 | -------------------------------------------------------------------------------- /usagi-api/model/usagi/code_mapping_conversion.py: -------------------------------------------------------------------------------- 1 | from peewee import AutoField, CharField, IntegerField, BigIntegerField 2 | from model.usagi.usagi_base_model import UsagiBaseModel 3 | 4 | 5 | class CodeMappingConversion(UsagiBaseModel): 6 | id = AutoField() 7 | username = CharField() 8 | status_code = IntegerField() 9 | status_name = CharField(max_length=25) 10 | 11 | class Meta: 12 | db_table = 'code_mapping_conversion' 13 | -------------------------------------------------------------------------------- /usagi-api/model/usagi/conversion_status.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class ConversionStatus(Enum): 5 | IN_PROGRESS = 1 6 | COMPLETED = 2 7 | ABORTED = 3 8 | FAILED = 4 -------------------------------------------------------------------------------- /usagi-api/model/usagi/log_status.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class LogStatus(Enum): 5 | INFO = 1 6 | DEBUG = 2 7 | WARNING = 3 8 | ERROR = 4 -------------------------------------------------------------------------------- /usagi-api/model/usagi/usagi_base_model.py: -------------------------------------------------------------------------------- 1 | from peewee import Model 2 | from util.usagi_db import usagi_pg_db 3 | 4 | 5 | class UsagiBaseModel(Model): 6 | class Meta: 7 | database = usagi_pg_db 8 | schema = 'usagi' 9 | -------------------------------------------------------------------------------- /usagi-api/model/usagi_data/atc_to_rxnorm.py: -------------------------------------------------------------------------------- 1 | from peewee import CharField, IntegerField, CompositeKey 2 | from model.usagi_data.usagi_data_base_model import UsagiDataBaseModel 3 | 4 | 5 | class atc_to_rxnorm(UsagiDataBaseModel): 6 | concept_code = CharField() 7 | concept_id_2 = IntegerField() 8 | 9 | class Meta: 10 | primary_key = CompositeKey('concept_code', 'concept_id_2') 11 | -------------------------------------------------------------------------------- /usagi-api/model/usagi_data/child.py: -------------------------------------------------------------------------------- 1 | from peewee import IntegerField 2 | from model.usagi_data.usagi_data_base_model import UsagiDataBaseModel 3 | 4 | 5 | class Child_Count(UsagiDataBaseModel): 6 | ancestor_concept_id = IntegerField() 7 | child_count = IntegerField() 8 | -------------------------------------------------------------------------------- /usagi-api/model/usagi_data/parent.py: -------------------------------------------------------------------------------- 1 | from peewee import IntegerField 2 | 3 | from model.usagi_data.usagi_data_base_model import UsagiDataBaseModel 4 | 5 | 6 | class Parent_Count(UsagiDataBaseModel): 7 | descendant_concept_id = IntegerField() 8 | parent_count = IntegerField() 9 | -------------------------------------------------------------------------------- /usagi-api/model/usagi_data/relations.py: -------------------------------------------------------------------------------- 1 | from peewee import IntegerField 2 | 3 | from model.usagi_data.usagi_data_base_model import UsagiDataBaseModel 4 | 5 | 6 | class Maps_To_Relationship(UsagiDataBaseModel): 7 | concept_id_1 = IntegerField() 8 | concept_id_2 = IntegerField() 9 | 10 | 11 | class Relationship_Atc_Rxnorm(UsagiDataBaseModel): 12 | concept_id_1 = IntegerField() 13 | concept_id_2 = IntegerField() 14 | 15 | 16 | class Parent_Child_Relationship(UsagiDataBaseModel): 17 | ancestor_concept_id = IntegerField() 18 | descendant_concept_id = IntegerField() -------------------------------------------------------------------------------- /usagi-api/model/usagi_data/usagi_data_base_model.py: -------------------------------------------------------------------------------- 1 | from peewee import Model 2 | from util.vocabulary_db import vocabulary_pg_db 3 | 4 | 5 | class UsagiDataBaseModel(Model): 6 | class Meta: 7 | database = vocabulary_pg_db 8 | schema = 'usagi_data' 9 | -------------------------------------------------------------------------------- /usagi-api/model/vocabulary/vocabulary_base_model.py: -------------------------------------------------------------------------------- 1 | from peewee import * 2 | from util.vocabulary_db import vocabulary_pg_db 3 | 4 | 5 | class VocabularyBaseModel(Model): 6 | class Meta: 7 | database = vocabulary_pg_db 8 | schema = 'vocabulary' 9 | -------------------------------------------------------------------------------- /usagi-api/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.0.3 2 | Flask_Cors==3.0.10 3 | pysolr==3.9.0 4 | peewee==3.14.8 5 | pandas~=1.3.5 6 | scikit-learn==0.24.2 7 | py-postgresql==1.2.1 8 | psycopg2-binary==2.9.3 9 | waitress==2.1.2 10 | SQLAlchemy==1.4.35 11 | APScheduler==3.9.1 12 | Werkzeug~=2.0.2 13 | requests~=2.27.1 14 | azure-identity==1.10.0 15 | azure-keyvault-secrets==4.4.0 -------------------------------------------------------------------------------- /usagi-api/sshd_config: -------------------------------------------------------------------------------- 1 | Port 2222 2 | ListenAddress 0.0.0.0 3 | LoginGraceTime 180 4 | X11Forwarding yes 5 | Ciphers aes128-cbc,3des-cbc,aes256-cbc 6 | MACs hmac-sha1,hmac-sha1-96 7 | StrictModes yes 8 | SyslogFacility DAEMON 9 | PasswordAuthentication yes 10 | PermitEmptyPasswords no 11 | PermitRootLogin yes -------------------------------------------------------------------------------- /usagi-api/util/array_util.py: -------------------------------------------------------------------------------- 1 | def remove_duplicates(results): 2 | return [i for n, i in enumerate(results) if i not in results[n + 1:]] -------------------------------------------------------------------------------- /usagi-api/util/code_mapping_conversion_util.py: -------------------------------------------------------------------------------- 1 | from model.usagi.code_mapping_conversion import CodeMappingConversion 2 | 3 | 4 | def code_mapping_conversion_to_json(conversion: CodeMappingConversion): 5 | return {'id': conversion.id, 6 | 'statusCode': conversion.status_code, 7 | 'statusName': conversion.status_name} 8 | -------------------------------------------------------------------------------- /usagi-api/util/constants.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | from app import app 4 | 5 | USAGI_CORE_NAME = 'usagi' 6 | 7 | SOLR_CONN_STRING = f"{app.config['SOLR_URL']}/solr/{USAGI_CORE_NAME}" 8 | 9 | CONCEPT_IDS = 'autoConceptId' 10 | SOURCE_CODE_TYPE_STRING = "S" 11 | 12 | SOLR_FILTERS = { 13 | 'vocabulary_id': 'vocabularies', 14 | 'concept_class_id': 'conceptClasses', 15 | 'domain_id': 'domains' 16 | } 17 | 18 | UPLOAD_SOURCE_CODES_FOLDER = Path('model/generate/source_codes') 19 | 20 | QUERY_SEARCH_MODE = 'query' 21 | 22 | INSERT_BATCH_SIZE = 10000 23 | -------------------------------------------------------------------------------- /usagi-api/util/conversion_id.py: -------------------------------------------------------------------------------- 1 | from flask import Request 2 | from util.exception import InvalidUsage 3 | 4 | 5 | def get_conversion_id(request: Request): 6 | conversion_id = request.args.get('conversionId', None, int) 7 | if conversion_id is None: 8 | raise InvalidUsage('Invalid conversion id', 400) 9 | return conversion_id -------------------------------------------------------------------------------- /usagi-api/util/exception.py: -------------------------------------------------------------------------------- 1 | class InvalidUsage(Exception): 2 | status_code = 400 3 | 4 | def __init__(self, message, status_code=None, base: Exception = None): 5 | Exception.__init__(self) \ 6 | if base is None \ 7 | else Exception.with_traceback(self, base.__traceback__) 8 | self.message = message 9 | if status_code is not None: 10 | self.status_code = status_code 11 | 12 | def to_dict(self): 13 | rv = dict() 14 | rv['message'] = self.message 15 | return rv 16 | 17 | def __str__(self): 18 | return self.message -------------------------------------------------------------------------------- /usagi-api/util/info_response.py: -------------------------------------------------------------------------------- 1 | from flask import jsonify 2 | 3 | from config import VERSION 4 | 5 | 6 | def info_response(): 7 | return jsonify({'name': 'Usagi', 'version': VERSION}) -------------------------------------------------------------------------------- /usagi-api/util/usagi_db.py: -------------------------------------------------------------------------------- 1 | from peewee import PostgresqlDatabase 2 | from app import app 3 | 4 | usagi_pg_db = PostgresqlDatabase(app.config["USAGI_DB_NAME"], 5 | user=app.config["USAGI_DB_USER"], 6 | password=app.config["USAGI_DB_PASSWORD"], 7 | host=app.config["USAGI_DB_HOST"], 8 | port=app.config["USAGI_DB_PORT"]) 9 | -------------------------------------------------------------------------------- /usagi-api/util/utils.py: -------------------------------------------------------------------------------- 1 | from flask import request 2 | from functools import wraps 3 | 4 | from util.exception import InvalidUsage 5 | 6 | 7 | def username_header(f): 8 | @wraps(f) 9 | def decorator(*args, **kwargs): 10 | current_user = request.headers.get('Username') 11 | if current_user is None: 12 | raise InvalidUsage('Username header not present') 13 | return f(current_user, *args, **kwargs) 14 | 15 | return decorator -------------------------------------------------------------------------------- /usagi-api/util/vocabulary_db.py: -------------------------------------------------------------------------------- 1 | from peewee import PostgresqlDatabase 2 | from app import app 3 | 4 | vocabulary_pg_db = PostgresqlDatabase(app.config["VOCABULARY_DB_NAME"], 5 | user=app.config["VOCABULARY_DB_USER"], 6 | password=app.config["VOCABULARY_DB_PASSWORD"], 7 | host=app.config["VOCABULARY_DB_HOST"], 8 | port=app.config["VOCABULARY_DB_PORT"]) 9 | -------------------------------------------------------------------------------- /user/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc -------------------------------------------------------------------------------- /user/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7 2 | ENV PYTHONDONTWRITEBYTECODE=1 3 | ENV PYTHONUNBUFFERED=1 4 | WORKDIR /app 5 | COPY requirements.txt /app/ 6 | RUN pip install -r requirements.txt 7 | COPY . /app/ 8 | 9 | RUN apt-get update \ 10 | && apt-get install -y --no-install-recommends openssh-server \ 11 | && export ROOTPASS=$(head -c 12 /dev/urandom |base64 -) && echo "root:$ROOTPASS" | chpasswd 12 | 13 | COPY sshd_config /etc/ssh/ 14 | COPY entrypoint.sh entrypoint.sh 15 | RUN chmod +x entrypoint.sh 16 | 17 | EXPOSE 5001 2222 18 | 19 | ENTRYPOINT ["./entrypoint.sh"] -------------------------------------------------------------------------------- /user/app.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from flask import Flask 3 | from flask_bcrypt import Bcrypt 4 | from flask_cors import CORS 5 | from app_config import init_app_config 6 | 7 | app = Flask(__name__) 8 | bcrypt = Bcrypt(app) 9 | init_app_config(app) 10 | CORS(app) 11 | logger = logging.getLogger('waitress') 12 | logger.setLevel(logging.INFO) 13 | app.logger = logger 14 | -------------------------------------------------------------------------------- /user/config.py: -------------------------------------------------------------------------------- 1 | PORT = 5001 2 | APP_PREFIX = '/user' 3 | VERSION = 0.4 4 | 5 | 6 | class LocalConfig: 7 | DB_NAME = 'shared' 8 | DB_USER = 'user' 9 | DB_PASSWORD = 'password' 10 | DB_HOST = 'localhost' 11 | DB_PORT = 5432 12 | 13 | 14 | class DockerConfig: 15 | DB_NAME = 'shared' 16 | DB_USER = 'user' 17 | DB_PASSWORD = 'password' 18 | DB_HOST = 'shareddb' 19 | DB_PORT = 5432 -------------------------------------------------------------------------------- /user/db.py: -------------------------------------------------------------------------------- 1 | from peewee import * 2 | from app import app 3 | 4 | pg_db = PostgresqlDatabase(app.config["DB_NAME"], user=app.config["DB_USER"], password=app.config["DB_PASSWORD"], 5 | host=app.config["DB_HOST"], port=app.config["DB_PORT"]) -------------------------------------------------------------------------------- /user/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | service ssh start 4 | python /app/main.py -------------------------------------------------------------------------------- /user/model/__init__.py: -------------------------------------------------------------------------------- 1 | from .blacklist_token import BlacklistToken 2 | from .user import User 3 | 4 | __all__ = ['BlacklistToken', 5 | 'User'] -------------------------------------------------------------------------------- /user/model/baseModel.py: -------------------------------------------------------------------------------- 1 | from peewee import Model 2 | from db import pg_db 3 | 4 | 5 | class BaseModel(Model): 6 | class Meta: 7 | database = pg_db 8 | schema = 'user' -------------------------------------------------------------------------------- /user/model/refresh_token.py: -------------------------------------------------------------------------------- 1 | from peewee import AutoField, CharField, DateTimeField 2 | 3 | from model.baseModel import BaseModel 4 | 5 | 6 | class RefreshToken(BaseModel): 7 | id = AutoField() 8 | email = CharField(unique=True) 9 | refresh_token = CharField() 10 | expiration_date = DateTimeField() 11 | 12 | class Meta: 13 | db_table = 'refresh_token' 14 | -------------------------------------------------------------------------------- /user/model/unauthorized_reset_pwd_request.py: -------------------------------------------------------------------------------- 1 | from peewee import AutoField, CharField, DateTimeField 2 | from model.baseModel import BaseModel 3 | 4 | 5 | class UnauthorizedResetPwdRequest(BaseModel): 6 | report_id = AutoField() 7 | username = CharField() 8 | report_date = DateTimeField() 9 | 10 | class Meta: 11 | db_table = 'unauthorized_reset_pwd_request' 12 | -------------------------------------------------------------------------------- /user/requirements.txt: -------------------------------------------------------------------------------- 1 | APScheduler==3.9.1 2 | cryptography==39.0.1 3 | Flask==2.0.3 4 | Flask_Bcrypt==0.7.1 5 | Flask_Cors==3.0.10 6 | peewee==3.14.10 7 | PyJWT==2.4.0 8 | waitress==2.1.2 9 | Werkzeug==2.2.3 10 | itsdangerous==2.0.1 11 | py-postgresql==1.2.2 12 | psycopg2-binary==2.9.3 13 | -------------------------------------------------------------------------------- /user/services/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/user/services/__init__.py -------------------------------------------------------------------------------- /user/sshd_config: -------------------------------------------------------------------------------- 1 | Port 2222 2 | ListenAddress 0.0.0.0 3 | LoginGraceTime 180 4 | X11Forwarding yes 5 | Ciphers aes128-cbc,3des-cbc,aes256-cbc 6 | MACs hmac-sha1,hmac-sha1-96 7 | StrictModes yes 8 | SyslogFacility DAEMON 9 | PasswordAuthentication yes 10 | PermitEmptyPasswords no 11 | PermitRootLogin yes -------------------------------------------------------------------------------- /user/user-envs.txt: -------------------------------------------------------------------------------- 1 | SMTP_SERVER= 2 | SMTP_PORT= 3 | SMTP_EMAIL= 4 | SMTP_USER= 5 | SMTP_PWD= 6 | TOKEN_SECRET_KEY=Perseus-Arcad!a 7 | EMAIL_SECRET_KEY=8cmuh4t5xTtR1EHaojWL0aqCR3vZ48PZF5AYkTe0iqo= 8 | USER_ENV=Docker 9 | SERVER_ADDRESS=http://localhost -------------------------------------------------------------------------------- /user/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareCountry/Perseus/1803a0e83938aa7caf2796acddac224c04f9fd25/user/utils/__init__.py -------------------------------------------------------------------------------- /user/utils/constants.py: -------------------------------------------------------------------------------- 1 | SMTP_PORT_STL = 587 2 | 3 | PASSWORD_LINK_EXPIRATION_TIME = 172800 # 48 hours 4 | REGISTRATION_LINK_EXPIRATION_TIME = 172800 # 48 hours 5 | USERNAME_HEADER = 'Username' 6 | AUTHORIZATION_HEADER = 'Authorization' -------------------------------------------------------------------------------- /user/utils/password.py: -------------------------------------------------------------------------------- 1 | from app import bcrypt, app 2 | 3 | 4 | def decode_password(password: str) -> str: 5 | return bcrypt.generate_password_hash( 6 | password, app.config.get('BCRYPT_LOG_ROUNDS') 7 | ).decode() -------------------------------------------------------------------------------- /user/utils/utils.py: -------------------------------------------------------------------------------- 1 | from app import app 2 | 3 | 4 | def getServerHostPort(host): 5 | if 'SERVER_PORT' in app.config: 6 | return f"http://{host}:{app.config['SERVER_PORT']}" 7 | else: 8 | return f"http://{host}" 9 | -------------------------------------------------------------------------------- /vocabulary-db/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres 2 | 3 | ARG INIT_ENV=full 4 | 5 | COPY vocabulary tmp/vocabulary 6 | COPY ${INIT_ENV}.sql /docker-entrypoint-initdb.d/ 7 | 8 | ENV POSTGRES_DB vocabulary 9 | ENV POSTGRES_USER admin 10 | ENV POSTGRES_PASSWORD password 11 | 12 | EXPOSE 5432 -------------------------------------------------------------------------------- /vocabulary-db/checkout.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TFS_HOST="dev.azure.com" 4 | TFS_COLLECTION="Softwarecountry-JNJ" 5 | TFS_PROJECT="Perseus" 6 | 7 | SCRIPT_PATH=`echo "$(dirname -- "$(readlink -f "${BASH_SOURCE}")")"` 8 | echo $SCRIPT_PATH && cd $SCRIPT_PATH 9 | 10 | PAT=$1 11 | PAT64=`printf "%s"":${PAT}" | base64` 12 | 13 | git -c http.extraHeader="Authorization: Basic ${PAT64}" clone https://${TFS_HOST}/${TFS_COLLECTION}/${TFS_PROJECT}/_git/vocabulary 14 | --------------------------------------------------------------------------------