├── .dockerignore ├── .gitignore ├── .rspec ├── .rubocop.yml ├── .rubocop_todo.yml ├── .stylelintrc.json ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── Makefile ├── Procfile ├── README.md ├── Rakefile ├── app ├── assets │ ├── images │ │ ├── favicon.ico │ │ └── patterns │ │ │ ├── header-profile.png │ │ │ └── shattered.png │ ├── javascripts │ │ ├── app │ │ │ ├── components │ │ │ │ ├── charts.js │ │ │ │ ├── dataTableShared.js │ │ │ │ ├── externalDataManipulation.js │ │ │ │ ├── faIcons.js │ │ │ │ ├── inlineEditing.js │ │ │ │ ├── layoutBuilderModal.js │ │ │ │ ├── listSort.js │ │ │ │ ├── modal.js │ │ │ │ ├── permissions_table.js │ │ │ │ └── tables.js │ │ │ ├── globals.js │ │ │ ├── navigation.js │ │ │ ├── registration.js │ │ │ ├── target_table_settings.js │ │ │ ├── twilio.js │ │ │ └── users.js │ │ ├── application.js │ │ ├── draggable.js │ │ ├── layout_builder.js │ │ ├── page_specific │ │ │ ├── adminUser.js │ │ │ ├── dashboard.js │ │ │ ├── database.js │ │ │ ├── layoutBuilder.js │ │ │ ├── organisationSetting.js │ │ │ ├── permissions.js │ │ │ ├── tables.js │ │ │ └── taskQueue.js │ │ ├── palomaInitializer.js │ │ └── task_queue_builder.js │ └── stylesheets │ │ ├── admin_users.scss │ │ ├── application.scss │ │ ├── base │ │ ├── activity.scss │ │ ├── buttons.scss │ │ ├── form.scss │ │ ├── globals.scss │ │ ├── margins_and_paddings.scss │ │ ├── media.scss │ │ ├── modal.scss │ │ ├── navigation.scss │ │ ├── typography.scss │ │ └── variables.scss │ │ ├── components │ │ ├── _toastr.scss │ │ └── _tooltipster.scss │ │ ├── dashboard.scss │ │ ├── devise.scss │ │ ├── layout_builder.scss │ │ ├── single_view_builder.scss │ │ ├── site.scss │ │ ├── table.scss │ │ ├── table_permissions.scss │ │ ├── task_queues.scss │ │ └── views.scss ├── controllers │ ├── activities_controller.rb │ ├── admin_user_registrations_controller.rb │ ├── admin_user_sessions_controller.rb │ ├── admin_users_controller.rb │ ├── application_controller.rb │ ├── call_controller.rb │ ├── concerns │ │ ├── .keep │ │ ├── database_actions.rb │ │ ├── database_presenter_actions.rb │ │ ├── license.rb │ │ ├── relatable_tables.rb │ │ ├── single_view_actions.rb │ │ ├── table_activity.rb │ │ ├── table_render.rb │ │ ├── task_queue_record_activity.rb │ │ ├── task_queue_render.rb │ │ └── user_abilities.rb │ ├── dashboard_controller.rb │ ├── data_table_states_controller.rb │ ├── databases_controller.rb │ ├── errors_controller.rb │ ├── home_controller.rb │ ├── layout_builder_controller.rb │ ├── organisation_settings_controller.rb │ ├── permissions_controller.rb │ ├── roles_controller.rb │ ├── tables_controller.rb │ ├── task_queues_controller.rb │ └── token_controller.rb ├── errors │ ├── invalid_client_database_error.rb │ ├── not_authorized_error.rb │ ├── sql_database_error.rb │ └── unable_to_save_record_error.rb ├── helpers │ ├── activity_helper.rb │ ├── application_helper.rb │ ├── devise_helper.rb │ ├── table_helper.rb │ └── view_builder_helper.rb ├── lib │ ├── assets │ │ └── .keep │ ├── catch_error_from_rack.rb │ ├── kuwinda │ │ ├── database_adapter.rb │ │ ├── gateway │ │ │ └── database_connection_gateway.rb │ │ ├── presenter │ │ │ ├── list_available_tables.rb │ │ │ ├── list_relatable_tables.rb │ │ │ ├── list_table_fields.rb │ │ │ ├── list_table_fields_with_type.rb │ │ │ └── retrieve_data.rb │ │ ├── repository │ │ │ └── target_db.rb │ │ └── use_case │ │ │ └── database_connection.rb │ ├── tasks │ │ ├── .keep │ │ ├── assets.rake │ │ ├── dummy_client_db_seeds.rake │ │ └── setup_staging_org_and_roles.rake │ └── twilio │ │ └── capability.rb ├── mailers │ └── .keep ├── models │ ├── .keep │ ├── ability.rb │ ├── activity.rb │ ├── admin_user.rb │ ├── application_record.rb │ ├── concerns │ │ ├── .keep │ │ ├── client_record.rb │ │ ├── database_connection.rb │ │ └── sensitive_data.rb │ ├── data_table_state.rb │ ├── database.rb │ ├── layout_setting.rb │ ├── organisation_setting.rb │ ├── permission.rb │ ├── role.rb │ ├── sql_filter.rb │ ├── sql_filter │ │ ├── base.rb │ │ └── equal.rb │ ├── sql_filter_factory.rb │ ├── target_table_setting.rb │ ├── task_queue.rb │ ├── task_queue_outcome.rb │ ├── view_builder.rb │ ├── work_list.rb │ └── work_list_outcome.rb ├── services │ └── verify_license_key_service.rb └── views │ ├── activities │ ├── _activity.html.erb │ ├── _form.html.erb │ ├── _task_queue_record_activity_form.html.erb │ ├── failure.js.erb │ ├── index.html.erb │ └── success.js.erb │ ├── admin_users │ ├── _new_modal.html.erb │ ├── _permissions.html.erb │ ├── _roles.html.erb │ ├── _show_modal.html.erb │ ├── _status.html.erb │ ├── _teams.html.erb │ ├── _user_form.html.erb │ ├── _users_table.html.erb │ ├── create_new.js.erb │ ├── delete_failure.js.erb │ ├── destroy.js.erb │ ├── edit.js.erb │ ├── index.html.erb │ ├── new.js.erb │ ├── show_modal.js.erb │ ├── update.js.erb │ ├── update_role.js.erb │ └── update_status.js.erb │ ├── dashboard │ ├── _license_form.html.erb │ ├── license.html.erb │ ├── show.html.erb │ └── verify_license.html.erb │ ├── databases │ ├── _credentials_form.html.erb │ ├── _mission_kontrol_relay_form.html.erb │ ├── _tabs.html.erb │ ├── create.js.erb │ ├── edit.html.erb │ ├── new.html.erb │ ├── test_connection.js.erb │ ├── test_gem.js.erb │ └── update.js.erb │ ├── devise │ ├── confirmations │ │ └── new.html.erb │ ├── mailer │ │ ├── confirmation_instructions.html.erb │ │ ├── email_changed.html.erb │ │ ├── password_change.html.erb │ │ ├── reset_password_instructions.html.erb │ │ └── unlock_instructions.html.erb │ ├── passwords │ │ ├── edit.html.erb │ │ └── new.html.erb │ ├── registrations │ │ ├── _form_content.html.erb │ │ ├── _form_content_admin_db.html.erb │ │ ├── _registration_form_one.html.erb │ │ ├── _registration_form_two.html.erb │ │ ├── edit.html.erb │ │ ├── edit.js.erb │ │ └── new.html.erb │ ├── sessions │ │ └── new.html.erb │ ├── shared │ │ └── _links.html.erb │ └── unlocks │ │ └── new.html.erb │ ├── errors │ ├── internal_server_error.html.erb │ ├── internal_server_error.js.erb │ ├── not_acceptable.html.erb │ ├── not_acceptable.js.erb │ ├── not_authorized.html.erb │ ├── not_authorized.js.erb │ ├── not_found.html.erb │ └── not_found.js.erb │ ├── home │ └── index.html.erb │ ├── layout_builder │ ├── _draggable_field_settings.html.erb │ ├── _field_settings_form_old.html.erb │ ├── _general_settings_form.html.erb │ ├── _initial_placeholder.html.erb │ ├── _record_placeholder_old.html.erb │ ├── configure_table_order_old.html.erb │ ├── edit.html.erb │ ├── edit │ │ ├── _layout_builder_editable_warning_modal_screen_1.html.erb │ │ ├── error.js.erb │ │ └── success.js.erb │ ├── index.html.erb │ ├── layout │ │ ├── _header_container1.html.erb │ │ ├── _header_container2.html.erb │ │ ├── _main_container1.html.erb │ │ ├── _main_container2.html.erb │ │ ├── _main_container3.html.erb │ │ └── _side_container.html.erb │ ├── new.html.erb │ ├── new │ │ ├── _layout_builder_modal_screen_1.html.erb │ │ └── _layout_builder_modal_screen_2.html.erb │ ├── preview.html.erb │ ├── select_table_fields.html.erb │ ├── show.html.erb │ └── update │ │ └── success.js │ ├── layouts │ ├── _footer.html.erb │ ├── _layout_builder_navigation.html.erb │ ├── _layout_builder_navigation_old.html.erb │ ├── _layout_builder_topnavbar.html.erb │ ├── _mouseflow.html.erb │ ├── _natterly.html │ ├── _navigation.html.erb │ ├── _task_queue_topnavbar.html.erb │ ├── _topnavbar.html.erb │ ├── application.html.erb │ ├── bad_connection.html.erb │ ├── dashboard.html.erb │ ├── layout_builder.html.erb │ ├── license.html.erb │ ├── standard.html.erb │ └── task_queue.html.erb │ ├── organisation_settings │ ├── edit.html.erb │ └── update.js.erb │ ├── permissions │ ├── add_to_role.js.erb │ ├── disable_all.js.erb │ ├── enable_all.js.erb │ ├── index.html.erb │ └── remove_from_role.js.erb │ ├── roles │ ├── _edit_modal.html.erb │ ├── edit.js.erb │ ├── update.js.erb │ └── update_error.js.erb │ ├── shared │ ├── _activity_history.html.erb │ ├── _activity_history_task_queue_item.html.erb │ ├── _activity_history_template.html.erb │ ├── _activity_stream.html.erb │ ├── _flash_message.html.erb │ ├── _page_banner_header.html.erb │ ├── _table_filter_bar.html.erb │ └── _task_queue_partial.html.erb │ ├── tables │ ├── _add_record_modal.html.erb │ ├── _data_table.html.erb │ ├── _edit_record_modal.html.erb │ ├── _record_placeholder_old.html.erb │ ├── _record_summary.html.erb │ ├── _related_data_table.html.erb │ ├── _related_table.html.erb │ ├── _related_table_with_layout.html.erb │ ├── _settings_modal.html.erb │ ├── _single_data_view.html.erb │ ├── _table.html.erb │ ├── _table_cell_data.html.erb │ ├── _table_with_layout.html.erb │ ├── _table_without_layout.html.erb │ ├── _twilio_dialer.html.erb │ ├── add_record.js.erb │ ├── create_record.js.erb │ ├── delete_record.js.erb │ ├── edit_record.js.erb │ ├── layout │ │ ├── _container_content.html.erb │ │ ├── _editable_actions.html.erb │ │ ├── _editable_input.html.erb │ │ ├── _header_container1.html.erb │ │ ├── _header_container2.html.erb │ │ ├── _main_container1.html.erb │ │ ├── _main_container2.html.erb │ │ ├── _main_container3.html.erb │ │ └── _side_container.html.erb │ ├── preview.html.erb │ ├── settings.js.erb │ ├── show.html.erb │ ├── show │ │ ├── failure.js.erb │ │ └── success.js.erb │ ├── update_record.js.erb │ └── update_settings.js.erb │ └── task_queues │ ├── _preview.html.erb │ ├── _preview_show.html.erb │ ├── _task_queue_builder.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── index_old.html.erb │ ├── new.html.erb │ ├── new │ ├── _new_queue_modal_screen_1.html.erb │ └── _new_queue_modal_screen_2.html.erb │ ├── shared │ ├── _task_queue_create_tab.html.erb │ ├── _task_queue_define_tab.html.erb │ ├── _task_queue_navigation.html.erb │ ├── _task_queue_outcome_settings.html.erb │ └── _task_queue_publish_tab.html.erb │ └── show.html.erb ├── bin ├── bundle ├── configure-host │ ├── README.md │ └── auto-install.sh ├── docker-entrypoint.sh ├── rails ├── rake ├── rspec ├── setup ├── update └── yarn ├── clock.rb ├── config.ru ├── config ├── application.rb ├── boot.rb ├── cable.yml ├── client_database.yml ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ ├── staging.rb │ └── test.rb ├── initializers │ ├── application_controller_renderer.rb │ ├── assets.rb │ ├── backtrace_silencers.rb │ ├── content_security_policy.rb │ ├── cookies_serializer.rb │ ├── devise.rb │ ├── feature_policy.rb │ ├── filter_parameter_logging.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── models.rb │ ├── new_framework_defaults_5_1.rb │ ├── new_framework_defaults_6_1.rb │ ├── rolify.rb │ ├── session_store.rb │ └── wrap_parameters.rb ├── locales │ ├── devise.en.yml │ └── en.yml ├── nginx_default.tmpl ├── puma.rb ├── routes.rb ├── secrets.yml ├── spring.rb └── storage.yml ├── db ├── migrate │ ├── 20180702090814_devise_create_users.rb │ ├── 20180703105143_rename_users_table.rb │ ├── 20181012143652_create_activities.rb │ ├── 20181018150144_remove_user_id_from_activities.rb │ ├── 20181018154253_add_polymorphic_assiociation_to_activities.rb │ ├── 20181104112129_create_table_view_builder.rb │ ├── 20181105125119_create_work_lists.rb │ ├── 20181108114556_add_sql_filters_to_work_lists.rb │ ├── 20181108143841_change_work_lists_sql_query_to_string.rb │ ├── 20181108144047_add_outcomes_to_work_lists.rb │ ├── 20181116183747_add_data_table_name_to_work_lists.rb │ ├── 20181122170852_add_visible_columns_to_work_list.rb │ ├── 20181123181141_add_view_name_to_view_builder.rb │ ├── 20181217165628_add_name_and_company_to_admin_users.rb │ ├── 20181224073927_create_layout_settings_table.rb │ ├── 20181224123606_add_visible_columns_to_layout_settings.rb │ ├── 20190107134016_add_show_status_to_view_builders.rb │ ├── 20190107134621_add_commentable_to_view_builders.rb │ ├── 20190107134849_add_parent_comment_table_to_view_builders.rb │ ├── 20190107135321_add_draggable_sections_to_view_builders.rb │ ├── 20190115204330_rename_draggable_containers_on_view_builders.rb │ ├── 20190303142750_add_hidden_columns_to_view_builder.rb │ ├── 20190303142916_drop_layout_settings.rb │ ├── 20190402151253_add_callable_fields_to_layout_builder.rb │ ├── 20190424163632_create_task_queues.rb │ ├── 20190425152656_add_query_builder_rules_to_task_queues.rb │ ├── 20190429161124_add_raw_sql_to_task_queues.rb │ ├── 20190513161432_add_query_builder_sql_to_task_queues.rb │ ├── 20190516152746_add_draggable_fields_to_task_queues.rb │ ├── 20190518152319_add_license_key_to_admin_users.rb │ ├── 20190528153818_add_outcome_settings_to_task_queues.rb │ ├── 20190531093327_add_full_license_to_admin_users.rb │ ├── 20190605161402_create_task_queue_outcomes.rb │ ├── 20190605161954_add_outcome_to_task_queue_outcomes.rb │ ├── 20190605164115_add_unique_constraint_to_task_queue_outcomes.rb │ ├── 20190620170803_add_related_tables_to_view_builder.rb │ ├── 20190627172016_create_data_table_states.rb │ ├── 20190807161323_add_ignore_layout_modal_to_admin_user.rb │ ├── 20190817190347_create_permissions.rb │ ├── 20190901110701_rolify_create_roles.rb │ ├── 20190901125126_create_organisation_settings.rb │ ├── 20191020103654_create_roles_permissions_table.rb │ ├── 20191107072022_add_status_to_admin_users.rb │ ├── 20191111185000_add_fields_to_roles.rb │ ├── 20191123165832_create_target_table_settings.rb │ ├── 20200111093456_add_database_table.rb │ ├── 20200126125119_add_database_id_to_target_table_settings.rb │ ├── 20200131135708_rename_database_password_field.rb │ ├── 20200325153714_add_editable_fields_to_target_table_settings.rb │ ├── 20200408133632_add_relay_gem_to_databases.rb │ ├── 20200417114658_add_database_id_to_view_builders.rb │ ├── 20200429134402_add_user_id_to_activity.rb │ ├── 20200507093234_add_database_id_to_task_queues.rb │ ├── 20200526152632_add_database_update_to_task_queues.rb │ ├── 20200528143521_add_enabled_field_to_task_queue.rb │ ├── 20200605105826_remove_null_restriction_task_queue_item.rb │ ├── 20200607113114_add_database_id_to_activities.rb │ ├── 20200628161055_create_active_storage_tables.active_storage.rb │ ├── 20200628161056_add_service_name_to_active_storage_blobs.active_storage.rb │ ├── 20200628161057_create_active_storage_variant_records.active_storage.rb │ ├── 20210117152849_remove_unique_constraint_task_queue_index.rb │ └── 20210130095843_add_primary_keys_to_target_table_settings.rb ├── schema.rb └── seeds.rb ├── docker-compose.yml ├── lib └── catch_error_from_rack.rb ├── log └── .keep ├── package-lock.json ├── public ├── 422.html ├── assets │ ├── .sprockets-manifest-45c6413dc95c4344a2238772146bbc2c.json │ ├── application-2de56da153daf022d256045cc5d53b7183a603e0af9863d1638f6087e9138d52.css │ ├── application-2de56da153daf022d256045cc5d53b7183a603e0af9863d1638f6087e9138d52.css.gz │ ├── application-60fcce1a154ba59fc56911eb77ae0500d846e0ab7b1bc414b9b6e497c632d2c1.js │ ├── application-60fcce1a154ba59fc56911eb77ae0500d846e0ab7b1bc414b9b6e497c632d2c1.js.gz │ ├── bootstrap │ │ ├── glyphicons-halflings-regular-13634da87d9e23f8c3ed9108ce1724d183a39ad072e73e1b3d8cbf646d2d0407.eot │ │ ├── glyphicons-halflings-regular-13634da87d9e23f8c3ed9108ce1724d183a39ad072e73e1b3d8cbf646d2d0407.eot.gz │ │ ├── glyphicons-halflings-regular-42f60659d265c1a3c30f9fa42abcbb56bd4a53af4d83d316d6dd7a36903c43e5.svg │ │ ├── glyphicons-halflings-regular-42f60659d265c1a3c30f9fa42abcbb56bd4a53af4d83d316d6dd7a36903c43e5.svg.gz │ │ ├── glyphicons-halflings-regular-a26394f7ede100ca118eff2eda08596275a9839b959c226e15439557a5a80742.woff │ │ ├── glyphicons-halflings-regular-e395044093757d82afcb138957d06a1ea9361bdcf0b442d06a18a8051af57456.ttf │ │ ├── glyphicons-halflings-regular-e395044093757d82afcb138957d06a1ea9361bdcf0b442d06a18a8051af57456.ttf.gz │ │ └── glyphicons-halflings-regular-fe185d11a49676890d47bb783312a0cda5a44c4039214094e7957b4c040ef11c.woff2 │ ├── dataTable │ │ ├── datatables.min-39255d21ad998b32b2fc7eb4a073a5e0b89acb2fcbdd1f90d9a6fc3aa43f656b.js │ │ └── datatables.min-39255d21ad998b32b2fc7eb4a073a5e0b89acb2fcbdd1f90d9a6fc3aa43f656b.js.gz │ ├── dragula │ │ ├── dragula.min-94edc9ac879d6bd3fbfa48b57d9742a08cadbbafe2f3233a1a9116c03f2b070f.js │ │ └── dragula.min-94edc9ac879d6bd3fbfa48b57d9742a08cadbbafe2f3233a1a9116c03f2b070f.js.gz │ ├── favicon-c14aaa6e1b7af86332a6497364938f801db6b1b3f4513dd70024bea60981a6ed.ico │ ├── favicon-c14aaa6e1b7af86332a6497364938f801db6b1b3f4513dd70024bea60981a6ed.ico.gz │ ├── fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2 │ ├── fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot │ ├── fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot.gz │ ├── fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf │ ├── fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf.gz │ ├── fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg │ ├── fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg.gz │ ├── fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff │ ├── images │ │ ├── Kuwinda_logo_full-blue-260.png │ │ └── icons │ │ │ ├── black-check-box-with-white-check.png │ │ │ ├── black-checkbox-empty.svg │ │ │ ├── blue_cat_loading.gif │ │ │ ├── checked-1.png │ │ │ ├── circle-with-check-symbol.png │ │ │ ├── circle-with-contrast.png │ │ │ ├── circle-with-cross.png │ │ │ ├── close.png │ │ │ ├── column.png │ │ │ ├── database-1.png │ │ │ ├── database-2.png │ │ │ ├── edit.png │ │ │ ├── edit@2x.png │ │ │ ├── export.png │ │ │ ├── group-3.png │ │ │ ├── import.png │ │ │ ├── magnifying-glass.png │ │ │ ├── minus-thick.png │ │ │ ├── plus-thick.png │ │ │ ├── plus.png │ │ │ ├── report.png │ │ │ ├── settings-1.png │ │ │ ├── settings-black.png │ │ │ ├── settings.png │ │ │ ├── team-1.png │ │ │ └── triangle.svg │ ├── logos │ │ ├── MissionKontrol-logo-inverted.png │ │ ├── MissionKontrol-logo-original.png │ │ └── kuwinda_thumbnail.png │ ├── moment │ │ ├── moment.min-a4f754452a828ad057b1b61c20fcb99251bb8fa7db0dba8ca96417b8e5d59c6c.js │ │ └── moment.min-a4f754452a828ad057b1b61c20fcb99251bb8fa7db0dba8ca96417b8e5d59c6c.js.gz │ ├── patterns │ │ ├── header-profile-c05909898218a521d3bd19ba09a9a43338de6de5fdf1d3fc771b0ec28ae416c5.png │ │ └── shattered-241155c2a3436bfc0a542fc31fe2908ff2bdfc90e1ac7e26c6ba715b01030dcf.png │ ├── query-builder │ │ ├── query-builder.min-252935bd0b5adbde13e1c5c616820f8a3a4f5cf645d690905bc728a80eeebe07.js │ │ └── query-builder.min-252935bd0b5adbde13e1c5c616820f8a3a4f5cf645d690905bc728a80eeebe07.js.gz │ ├── shopify │ │ ├── draggable.bundle-06c5ee80a53567c4a8f91f12174da87600991bb912404d73dbc1e66cbd8b2c94.js │ │ ├── draggable.bundle-06c5ee80a53567c4a8f91f12174da87600991bb912404d73dbc1e66cbd8b2c94.js.gz │ │ ├── sortable-8042a7900fcf2bf2e78d523d4cc0b896ec1151b893c9fe62dc702d6e047df669.js │ │ └── sortable-8042a7900fcf2bf2e78d523d4cc0b896ec1151b893c9fe62dc702d6e047df669.js.gz │ └── sweetAlert │ │ ├── sweetalert.min-c517df19a3eecca1c27936dfafd34163d0c1c81271aa6f914db8d5b1e7731d2f.js │ │ └── sweetalert.min-c517df19a3eecca1c27936dfafd34163d0c1c81271aa6f914db8d5b1e7731d2f.js.gz ├── favicon.ico └── robots.txt ├── spec ├── factories │ ├── activity.rb │ ├── admin_user.rb │ ├── database.rb │ ├── organisation_setting.rb │ ├── permission.rb │ ├── role.rb │ ├── target_table_setting.rb │ ├── task_queue.rb │ ├── user.rb │ ├── view_builder.rb │ └── work_list.rb ├── features │ ├── cache_connection_spec.rb │ ├── single_data_view │ │ ├── create_single_data_view_spec.rb │ │ └── dragging_primary_fields_to_container_spec.rb │ ├── tables │ │ ├── add_record_spec.rb │ │ ├── admin_views_table_detail_without_layout_spec.rb │ │ ├── admin_views_table_spec.rb │ │ ├── delete_records_spec.rb │ │ ├── edit_record_spec.rb │ │ └── settings_spec.rb │ └── users │ │ ├── admin_log_in_spec.rb │ │ ├── permissions_spec.rb │ │ └── registration_spec.rb ├── fixtures │ ├── events.yml │ └── users.yml ├── rails_helper.rb ├── spec_helper.rb ├── support │ ├── features │ │ ├── session_helpers.rb │ │ ├── table_session_helpers.rb │ │ └── target_database_helpers.rb │ ├── time_helpers.rb │ ├── unit │ │ ├── fake_active_record.rb │ │ └── session_helpers.rb │ └── wait_for_ajax.rb └── unit │ ├── controllers │ ├── dashboard_controller_spec.rb │ ├── databases_controller_spec.rb │ ├── layout_builder_controller_spec.rb │ ├── organisation_settings_controller_spec.rb │ ├── permissions_controller_spec.rb │ ├── roles_controller_spec.rb │ ├── tables_controller_spec.rb │ └── task_queues_controller_spec.rb │ ├── lib │ └── kuwinda │ │ ├── database_adapter_spec.rb │ │ ├── gateway │ │ └── database_connection_gateway_spec.rb │ │ ├── presenter │ │ ├── list_available_tables_spec.rb │ │ ├── list_relatable_tables_spec.rb │ │ ├── list_table_fields_spec.rb │ │ ├── list_table_fields_with_type_spec.rb │ │ └── retrieve_data_spec.rb │ │ ├── repository │ │ └── target_db_spec.rb │ │ └── use_case │ │ └── database_connection_spec.rb │ ├── models │ ├── activity_spec.rb │ ├── admin_user_spec.rb │ ├── concerns │ │ └── sensitive_data_spec.rb │ ├── data_table_state_spec.rb │ ├── database_spec.rb │ ├── role_spec.rb │ ├── sql_filter_factory_spec.rb │ ├── sql_filter_spec.rb │ ├── target_table_setting_spec.rb │ ├── task_queue_spec.rb │ ├── view_builder_spec.rb │ └── work_list_spec.rb │ └── services │ └── verify_license_key_service_spec.rb └── vendor └── assets ├── fonts └── Casino_Hand │ ├── casino_hand-webfont.eot │ ├── casino_hand-webfont.svg │ ├── casino_hand-webfont.ttf │ └── casino_hand-webfont.woff ├── images ├── animated-overlay.gif ├── blueimp │ └── img │ │ ├── error.png │ │ ├── error.svg │ │ ├── loading.gif │ │ ├── play-pause.png │ │ ├── play-pause.svg │ │ ├── video-play.png │ │ └── video-play.svg ├── bootstrap-colorpicker │ ├── alpha-horizontal.png │ ├── alpha.png │ ├── hue-horizontal.png │ ├── hue.png │ └── saturation.png ├── chosen-sprite.png ├── chosen-sprite@2x.png ├── green.png ├── green@2x.png ├── iCheck │ ├── green.png │ └── green@2x.png ├── images │ ├── animated-overlay.gif │ ├── ui-bg_flat_0_aaaaaa_40x100.png │ ├── ui-bg_flat_75_ffffff_40x100.png │ ├── ui-bg_glass_55_fbf9ee_1x400.png │ ├── ui-bg_glass_65_ffffff_1x400.png │ ├── ui-bg_glass_75_dadada_1x400.png │ ├── ui-bg_glass_75_e6e6e6_1x400.png │ ├── ui-bg_glass_95_fef1ec_1x400.png │ ├── ui-bg_highlight-soft_75_cccccc_1x100.png │ ├── ui-icons_222222_256x240.png │ ├── ui-icons_2e83ff_256x240.png │ ├── ui-icons_454545_256x240.png │ ├── ui-icons_888888_256x240.png │ └── ui-icons_cd0a0a_256x240.png ├── sort.png ├── sort_asc.png ├── sort_desc.png ├── sprite-skin-flat.png ├── sprite-skin-flat2.png ├── sprite-skin-nice.png ├── sprite-skin-simple.png ├── spritemap.png └── spritemap@2x.png ├── javascripts ├── .keep ├── bootstrap │ └── bootstrap-datepicker.js ├── dataTable │ └── datatables.min.js ├── dotjs │ └── doT.min.js ├── dragula │ └── dragula.min.js ├── dualListbox │ └── jquery.bootstrap-duallistbox.js ├── enjoyhint │ └── enjoyhint.js ├── extendext │ └── jQuery.extendext.min.js ├── flot │ ├── curvedLines.js │ ├── excanvas.min.js │ ├── jquery.flot.js │ ├── jquery.flot.pie.js │ ├── jquery.flot.resize.js │ ├── jquery.flot.spline.js │ ├── jquery.flot.symbol.js │ ├── jquery.flot.time.js │ └── jquery.flot.tooltip.min.js ├── inspinia │ └── inspinia.js ├── jquery │ └── jquery-3.1.1.min.js ├── metisMenu │ └── jquery.metisMenu.js ├── moment │ └── moment.min.js ├── query-builder │ └── query-builder.min.js ├── shopify │ ├── draggable.bundle.js │ └── sortable.js ├── sweetAlert │ └── sweetalert.min.js ├── toastr │ └── toastr.min.js └── tooltipster │ └── tooltipster.bundle.min.js └── stylesheets ├── dataTable └── datatables.scss ├── dragula └── dragula.min.css ├── images ├── bootstrap-colorpicker │ ├── alpha-horizontal.png │ ├── alpha.png │ ├── hue-horizontal.png │ ├── hue.png │ └── saturation.png ├── sort.png ├── sort_asc.png ├── sort_desc.png ├── sprite-skin-flat.png ├── sprite-skin-flat2.png ├── sprite-skin-nice.png ├── sprite-skin-simple.png ├── spritemap.png └── spritemap@2x.png ├── jQueryUI ├── images │ ├── animated-overlay.gif │ ├── ui-bg_flat_0_aaaaaa_40x100.png │ ├── ui-bg_flat_75_ffffff_40x100.png │ ├── ui-bg_glass_55_fbf9ee_1x400.png │ ├── ui-bg_glass_65_ffffff_1x400.png │ ├── ui-bg_glass_75_dadada_1x400.png │ ├── ui-bg_glass_75_e6e6e6_1x400.png │ ├── ui-bg_glass_95_fef1ec_1x400.png │ ├── ui-bg_highlight-soft_75_cccccc_1x100.png │ ├── ui-icons_222222_256x240.png │ ├── ui-icons_2e83ff_256x240.png │ ├── ui-icons_454545_256x240.png │ ├── ui-icons_888888_256x240.png │ └── ui-icons_cd0a0a_256x240.png ├── jquery-ui-1.10.4.custom.min.css └── jquery-ui.css ├── query-builder └── query-builder.default.min.css ├── toastr └── toastr.min.css └── tooltipster ├── tooltipster-sideTip-shadow.min.css └── tooltipster.bundle.min.css /.dockerignore: -------------------------------------------------------------------------------- 1 | log/* 2 | ssl/* 3 | tmp/* 4 | .git 5 | 6 | Dockerfile 7 | Makefile 8 | .bash_history 9 | docker-compose.yml 10 | .env 11 | 12 | spec/ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | .env 10 | 11 | # Ignore all logfiles and tempfiles. 12 | /log/* 13 | !/log/.keep 14 | /tmp 15 | .bash_history 16 | .env 17 | ssl 18 | 19 | .byebug_history 20 | 21 | Guardfile 22 | 23 | config/admin_db_* 24 | config/target_db_* 25 | config/sensitive_data/* 26 | 27 | .env 28 | .ruby-version 29 | .DS_Store 30 | 31 | coverage/ 32 | 33 | node_modules/ 34 | 35 | custom_plan.rb 36 | zeus.json -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --require spec_helper 2 | --require rails_helper 3 | --format documentation 4 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_from: .rubocop_todo.yml 2 | 3 | AllCops: 4 | Exclude: 5 | - 'db/schema.rb' 6 | - 'config/initializers/devise.rb' 7 | - 'db/migrate/*' 8 | - 'Guardfile' 9 | - 'bin/*' 10 | - 'config/*' 11 | - 'Rakefile' 12 | 13 | Documentation: 14 | Enabled: false 15 | 16 | Metrics/BlockLength: 17 | ExcludedMethods: ['describe', 'context', 'feature'] 18 | 19 | Metrics/ClassLength: 20 | Exclude: 21 | - 'app/lib/kuwinda/repository/target_db.rb' 22 | 23 | Metrics/ModuleLength: 24 | Max: 200 25 | Exclude: 26 | - 'spec/unit/lib/kuwinda/repository/target_db_spec.rb' 27 | 28 | Layout/FirstArrayElementIndentation: 29 | Exclude: 30 | - 'db/seeds.rb' 31 | -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard", 3 | "rules": { 4 | "no-descending-specificity": null, 5 | "at-rule-no-unknown": [ 6 | true, 7 | { 8 | "ignoreAtRules": ["extend"] 9 | } 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | start: 2 | docker-compose build 3 | docker-compose up -d 4 | 5 | stop: 6 | docker-compose stop 7 | 8 | restart: stop start 9 | 10 | clean: 11 | docker-compose down -v 12 | 13 | bash: 14 | docker-compose run --rm --service-ports web 15 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: bin/rails server -p $PORT -e $RAILS_ENV 2 | worker: bundle exec clockwork clock.rb 3 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /app/assets/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/app/assets/images/favicon.ico -------------------------------------------------------------------------------- /app/assets/images/patterns/header-profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/app/assets/images/patterns/header-profile.png -------------------------------------------------------------------------------- /app/assets/images/patterns/shattered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/app/assets/images/patterns/shattered.png -------------------------------------------------------------------------------- /app/assets/javascripts/app/components/charts.js: -------------------------------------------------------------------------------- 1 | //= require flot/jquery.flot.js 2 | //= require flot/jquery.flot.spline.js 3 | -------------------------------------------------------------------------------- /app/assets/javascripts/app/components/faIcons.js: -------------------------------------------------------------------------------- 1 | function replaceArrowGlypicon () { 2 | $(".glyphicon-arrow-right").addClass("fa fa-arrow-right").removeClass("glyphicon glyphicon-arrow-right"); 3 | $(".glyphicon-arrow-left").addClass("fa fa-arrow-left").removeClass("glyphicon glyphicon-arrow-left"); 4 | } 5 | 6 | $(document).ready(function() { 7 | replaceArrowGlypicon(); 8 | }); 9 | -------------------------------------------------------------------------------- /app/assets/javascripts/app/components/listSort.js: -------------------------------------------------------------------------------- 1 | // var ready, setPositions; 2 | 3 | // setPositions = function(){ 4 | // $(".tableField").each(function(i){ 5 | // $(this).attr("data-pos",i+1); 6 | // }); 7 | // } 8 | 9 | // ready = function(){ 10 | // setPositions(); 11 | 12 | // sortable(".sortable"); 13 | 14 | // if (sortable(".sortable")[0]) { 15 | // sortable(".sortable")[0].addEventListener("sortupdate", function(e, ui) { 16 | // // array to store new order 17 | // updatedOrder = []; 18 | // // set the updated positions 19 | // setPositions(); 20 | 21 | // // populate the updatedOrder array with the new task positions 22 | // $(".tableField").each(function(i){ 23 | // updatedOrder.push({ value: $(this).data("value"), position: i+1 }); 24 | // }); 25 | // }); 26 | // } 27 | // } 28 | 29 | // $(document).ready(ready); 30 | // /** 31 | // * if using turbolinks 32 | // */ 33 | // $(document).on("page:load", ready); 34 | -------------------------------------------------------------------------------- /app/assets/javascripts/app/components/modal.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function closeModal() { 4 | $("body").on("click", ".modal--close-btn", function () { 5 | var modal = $(this).parents(".show"); 6 | modal.removeClass("show"); 7 | modal.addClass("hide"); 8 | $("button.table--settings").attr("disabled", false); 9 | }); 10 | } 11 | 12 | $(document).ready(function () { 13 | closeModal(); 14 | }); -------------------------------------------------------------------------------- /app/assets/javascripts/app/components/tables.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/app/assets/javascripts/app/components/tables.js -------------------------------------------------------------------------------- /app/assets/javascripts/app/registration.js: -------------------------------------------------------------------------------- 1 | function goToRegistrationStep(step) { 2 | $("#registration-step-1, #registration-step-2").toggleClass("hide"); 3 | } 4 | 5 | function checkPasswordMatch() { 6 | let password = $("#admin_user_password").val(); 7 | let confirmPassword = $("#admin_user_password_confirmation").val(); 8 | 9 | if (password === confirmPassword) { 10 | $("#password-mismatch").hide(); 11 | $("#next-registration-step").attr("disabled", false); 12 | } else { 13 | $("#password-mismatch").show(); 14 | $("#next-registration-step").attr("disabled", true); 15 | } 16 | } 17 | 18 | $(document).ready(function () { 19 | $("#password-mismatch").hide(); 20 | $("#admin_user_password, #admin_user_password_confirmation").keyup(function() { 21 | checkPasswordMatch(); 22 | }); 23 | }); 24 | 25 | -------------------------------------------------------------------------------- /app/assets/javascripts/app/target_table_settings.js: -------------------------------------------------------------------------------- 1 | function toggleCheckbox () { 2 | $("body").on("change", ".toggle-state:checkbox", function (e) { 3 | let value = $(this).val(); 4 | if (value === "false") { 5 | $(this).val("true"); 6 | } else if (value === "true") { 7 | $(this).val("false"); 8 | } 9 | }); 10 | } 11 | 12 | $(document).ready(function() { 13 | toggleCheckbox(); 14 | }); -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // 8 | //= require jquery/jquery-3.1.1.min.js 9 | //= require rails-ujs 10 | //= require inspinia/inspinia 11 | //= require bootstrap-sprockets 12 | //= require metisMenu/jquery.metisMenu.js 13 | //= require toastr/toastr.min.js 14 | //= require dualListbox/jquery.bootstrap-duallistbox.js 15 | //= require extendext/jQuery.extendext.min.js 16 | //= require dotjs/doT.min.js 17 | //= require bootstrap/bootstrap-datepicker.js 18 | //= require tooltipster/tooltipster.bundle.min.js 19 | //= require paloma 20 | //= require palomaInitializer 21 | //= require_tree . 22 | //= require draggable 23 | //= require layout_builder 24 | //= require task_queue_builder 25 | -------------------------------------------------------------------------------- /app/assets/javascripts/page_specific/adminUser.js: -------------------------------------------------------------------------------- 1 | function submitSettingsChange () { 2 | $("body").on("change", "#role--edit-settings:checkbox", function () { 3 | var id = $(this).data("role"); 4 | var setting = $(this).data("setting"); 5 | $.ajax({ 6 | method: "PUT", 7 | url: "/roles", 8 | data: { 9 | id: id, 10 | setting: setting 11 | }, 12 | }); 13 | }); 14 | 15 | $("body").on("change", "#role--export-limit", function () { 16 | var id = $(this).data("role"); 17 | var limit = $(this).val(); 18 | $.ajax({ 19 | method: "PUT", 20 | url: "/roles", 21 | data: { 22 | id: id, 23 | limit: limit 24 | }, 25 | }) 26 | }); 27 | } 28 | 29 | Paloma.controller("AdminUsers", { 30 | index () { 31 | submitSettingsChange(); 32 | } 33 | }); 34 | -------------------------------------------------------------------------------- /app/assets/javascripts/page_specific/dashboard.js: -------------------------------------------------------------------------------- 1 | Paloma.controller("Dashboard", { 2 | show () { 3 | $(".spinner").hide(); 4 | } 5 | }); -------------------------------------------------------------------------------- /app/assets/javascripts/page_specific/database.js: -------------------------------------------------------------------------------- 1 | function submitPasswordChange () { 2 | $("input#database_password").on("change", function () { 3 | $("#database_password_changed").val(true); 4 | }); 5 | } 6 | 7 | function clearGemCredentials () { 8 | $("#remove-gem-connection").on("click", function () { 9 | $("#database_domain_url").val(""); 10 | $("#database_gem_token").val(""); 11 | }); 12 | } 13 | 14 | Paloma.controller("Databases", { 15 | new () { 16 | submitPasswordChange(); 17 | }, 18 | 19 | edit () { 20 | submitPasswordChange(); 21 | clearGemCredentials(); 22 | } 23 | }); -------------------------------------------------------------------------------- /app/assets/javascripts/page_specific/organisationSetting.js: -------------------------------------------------------------------------------- 1 | Paloma.controller("OrganisationSettings", { 2 | edit () { 3 | $(".spinner").hide(); 4 | } 5 | }); -------------------------------------------------------------------------------- /app/assets/javascripts/page_specific/permissions.js: -------------------------------------------------------------------------------- 1 | Paloma.controller("Permissions", { 2 | index () { 3 | $(".spinner").hide(); 4 | } 5 | }); -------------------------------------------------------------------------------- /app/assets/javascripts/palomaInitializer.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | Paloma.start(); 3 | $.fn.dataTable.ext.errMode = 'throw'; 4 | 5 | }); 6 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the top of the 9 | * compiled file, but it's generally better to create a new file per style scope. 10 | * 11 | 12 | *= require toastr/toastr.min.css 13 | *= require query-builder/query-builder.default.min.css 14 | *= require dataTable/datatables.scss 15 | *= require jQueryUI/jquery-ui.css 16 | *= require dragula/dragula.min.css 17 | *= require tooltipster/tooltipster.bundle.min.css 18 | *= require tooltipster/tooltipster-sideTip-shadow.min.css 19 | *= require font-awesome 20 | *= require site 21 | *= require devise 22 | *= require_self 23 | */ 24 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/_toastr.scss: -------------------------------------------------------------------------------- 1 | .toast { 2 | background-color: #030303; 3 | } 4 | 5 | .toast-success { 6 | background-color: $blueberry; 7 | } 8 | 9 | .toast-error { 10 | background-color: $info-red; 11 | } 12 | 13 | .toast-info { 14 | background-color: $cool-blue; 15 | } 16 | 17 | .toast-warning { 18 | background-color: $dark-salmon; 19 | } 20 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/_tooltipster.scss: -------------------------------------------------------------------------------- 1 | .tooltip_templates { 2 | position: relative; 3 | opacity: 1; 4 | } 5 | 6 | .tooltipster-sidetip.tooltipster-shadow.tooltipster-shadow-customized { 7 | .tooltipster-content { 8 | width: 125px; 9 | height: 64px; 10 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.2); 11 | text-align: center; 12 | font-size: 14px; 13 | } 14 | 15 | #tooltip_content { 16 | vertical-align: middle; 17 | padding-top: 6px; 18 | 19 | a { 20 | color: $link-gray; 21 | 22 | &:hover { 23 | color: $purple; 24 | font-weight: bold; 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/assets/stylesheets/dashboard.scss: -------------------------------------------------------------------------------- 1 | .dashboard--title { 2 | padding-left: 3%; 3 | height: 5%; 4 | } 5 | 6 | .dashboard--system { 7 | padding-top: 15px; 8 | } 9 | 10 | .dashboard--trial-license { 11 | border: solid 0.5px $blueberry; 12 | background-color: $white; 13 | padding-left: 3%; 14 | padding-bottom: 1%; 15 | } 16 | 17 | .dashboard--panels { 18 | margin-top: 30px; 19 | } 20 | 21 | .dashboard--panel { 22 | background-color: $white; 23 | height: 200px; 24 | padding: 15px; 25 | padding-top: 22px; 26 | text-align: center; 27 | 28 | img { 29 | height: 80px; 30 | } 31 | } 32 | 33 | [data-link] { 34 | cursor: pointer; 35 | } 36 | 37 | .spinner { 38 | position: absolute; 39 | z-index: 1000; 40 | left: 50%; 41 | top: 45%; 42 | background-color: $white; 43 | border: solid 0.5px $blueberry; 44 | border-radius: 100%; 45 | 46 | img { 47 | border-radius: 100%; 48 | padding: 0.6em; 49 | width: 96px; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/assets/stylesheets/site.scss: -------------------------------------------------------------------------------- 1 | // Google Fonts 2 | @import url("https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700&lang=en&display=swap"); 3 | 4 | // Bootstrap 5 | @import "bootstrap-sprockets"; 6 | @import "bootstrap"; 7 | 8 | // Variables, Mixins, Base 9 | @import "base/variables"; 10 | @import "base/typography"; 11 | @import "base/globals.scss"; 12 | @import "base/margins_and_paddings"; 13 | @import "base/navigation"; 14 | @import "base/buttons"; 15 | @import "base/modal"; 16 | @import "base/form"; 17 | @import "base/activity"; 18 | @import "views"; 19 | @import "admin_users"; 20 | @import 'table'; 21 | @import 'layout_builder'; 22 | @import 'single_view_builder'; 23 | @import 'task_queues'; 24 | @import 'dashboard'; 25 | @import 'table_permissions'; 26 | @import 'components/tooltipster'; 27 | @import 'components/toastr'; 28 | @import "base/media"; 29 | 30 | // Clear layout on print mode 31 | @media print { 32 | nav.navbar-static-side { 33 | display: none; 34 | } 35 | 36 | body { overflow: visible !important; } 37 | 38 | #page-wrapper { 39 | margin: 0; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/assets/stylesheets/views.scss: -------------------------------------------------------------------------------- 1 | .display-inline { 2 | display: inline-block; 3 | } 4 | 5 | span.editable-actions { 6 | margin-left: 5px; 7 | } 8 | -------------------------------------------------------------------------------- /app/controllers/admin_user_sessions_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AdminUserSessionsController < Devise::SessionsController 4 | before_action :check_admin_user_exists, only: [:new] 5 | 6 | private 7 | 8 | def check_admin_user_exists 9 | redirect_path = OrganisationSetting.any? && AdminUser.any? ? nil : new_admin_user_registration_path 10 | 11 | redirect_to redirect_path if redirect_path.present? 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/controllers/call_controller.rb: -------------------------------------------------------------------------------- 1 | class CallController < ApplicationController 2 | skip_before_action :verify_authenticity_token 3 | 4 | def connect 5 | render xml: twilio_reponse 6 | end 7 | 8 | private 9 | 10 | def twilio_reponse 11 | admin = AdminUser.last 12 | 13 | res = Twilio::TwiML::VoiceResponse.new do |response| 14 | dial = Twilio::TwiML::Dial.new caller_id: admin.twilio_caller_id 15 | dial.number params[:phoneNumber] 16 | response.append(dial) 17 | end 18 | return res.to_s 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /app/controllers/concerns/relatable_tables.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module RelatableTables 4 | extend ActiveSupport::Concern 5 | 6 | private 7 | 8 | def set_relatable_tables 9 | @relatable_tables = [] 10 | 11 | relatable_tables(@current_table).each do |table| 12 | # layout = ViewBuilder.find_by_table_name(table) 13 | relative = {} 14 | # @target_db.table = table 15 | foreign_key_title = helpers.get_foreign_key(params[:table_name]) 16 | foreign_key_value = params[:record_id] 17 | sql_result = @target_db.find_all_related(table, foreign_key_title, foreign_key_value, 10, 0) 18 | relative[:headers] = sql_result ? sql_result.columns : [] 19 | relative[:name] = table 20 | @relatable_tables << relative 21 | end 22 | 23 | @relatable_tables 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /app/controllers/concerns/user_abilities.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module UserAbilities 4 | extend ActiveSupport::Concern 5 | 6 | private 7 | 8 | def check_user_admin_abilities 9 | redirect_to(root_path) unless current_admin_user.admin_abilities? 10 | end 11 | 12 | def check_user_editor_abilities 13 | redirect_to(root_path) unless current_admin_user.editor_abilities? || current_admin_user.admin_abilities? 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/controllers/data_table_states_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class DataTableStatesController < ApplicationController 4 | def load 5 | dts = DataTableState.find_by_table(params[:table]) 6 | respond_to do |format| 7 | format.js do 8 | if dts 9 | render json: dts.state_as_json 10 | else 11 | render json: {} 12 | end 13 | end 14 | end 15 | end 16 | 17 | def save 18 | dts = DataTableState.where(table: params[:table]).first_or_create 19 | dts.state = state_params.to_h 20 | dts.table = params[:table] 21 | dts.save 22 | 23 | respond_to do |format| 24 | format.js do 25 | render json: dts.state_as_json 26 | end 27 | end 28 | end 29 | 30 | private 31 | 32 | def state_params 33 | params.require(:state).permit! 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /app/controllers/errors_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ErrorsController < ApplicationController 4 | def not_found 5 | respond_to do |format| 6 | format.html { render status: 404, layout: 'dashboard' } 7 | format.js { render status: 404, layout: 'dashboard' } 8 | end 9 | end 10 | 11 | def internal_server_error 12 | respond_to do |format| 13 | format.html { render status: 500, layout: 'dashboard' } 14 | format.js { render status: 500, layout: 'dashboard' } 15 | end 16 | end 17 | 18 | def not_acceptable 19 | respond_to do |format| 20 | format.html { render status: 406, layout: 'dashboard' } 21 | format.js { render status: 406, layout: 'dashboard' } 22 | end 23 | end 24 | 25 | def not_authorized 26 | respond_to do |format| 27 | format.html { render status: 401, layout: 'dashboard' } 28 | format.js { render status: 401, layout: 'dashboard' } 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class HomeController < ApplicationController 4 | def index 5 | redirect_to dashboard_path if admin_user_signed_in? 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/controllers/organisation_settings_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class OrganisationSettingsController < ApplicationController 4 | include UserAbilities 5 | 6 | layout 'standard' 7 | 8 | before_action :check_user_admin_abilities, only: %i[edit] 9 | 10 | def edit 11 | @organisation = OrganisationSetting.find params[:id] 12 | end 13 | 14 | def update 15 | @organisation = OrganisationSetting.find params[:id] 16 | unchanged_key = organisation_params[:license_key] == @organisation.license_key 17 | 18 | unless unchanged_key 19 | valid_license = activate_license(organisation_params[:license_key]) 20 | @invalid_key = !valid_license 21 | end 22 | 23 | @result = @organisation.update!(organisation_params) if valid_license || unchanged_key 24 | end 25 | 26 | private 27 | 28 | def organisation_params 29 | params.require(:organisation_setting).permit(:company_name, :license_key) 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /app/controllers/token_controller.rb: -------------------------------------------------------------------------------- 1 | class TokenController < ApplicationController 2 | skip_before_action :verify_authenticity_token 3 | 4 | ## TODO: FIX THIS SHIT 5 | def generate 6 | # token = Rails.env.test? ? 'token' : ::Twilio::Capability.generate(current_admin_user) 7 | 8 | render json: { token: 'token' } 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/errors/invalid_client_database_error.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class InvalidClientDatabaseError < StandardError 4 | def initialize(msg = 'Client database is invalid') 5 | super 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/errors/not_authorized_error.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class NotAuthorizedError < StandardError 4 | def initialize(msg = 'Not authorized to perform this action') 5 | super 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/errors/sql_database_error.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class SqlDatabaseError < StandardError 4 | def initialize(msg = 'Something went wrong with the SQL query.') 5 | super 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/errors/unable_to_save_record_error.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class UnableToSaveRecordError < StandardError 4 | def initialize(msg = 'Something went wrong and we cannot save the record') 5 | super 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/helpers/activity_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ActivityHelper 4 | def render_activity(activity) 5 | name = activity.admin_user == current_admin_user ? 'You' : activity.admin_user.full_name 6 | case activity.kind 7 | when 'note' 8 | content_tag(:strong, name) + 9 | content_tag(:span, ' added a ') + 10 | content_tag(:strong, 'comment: ') + 11 | content_tag(:span, activity.content.to_s) 12 | when 'outcome' 13 | content_tag(:strong, name) + 14 | content_tag(:span, ' added a ') + 15 | content_tag(:strong, 'tag: ') + 16 | content_tag(:span, activity.content.to_s) 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /app/helpers/devise_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DeviseHelper 4 | def devise_error_messages! 5 | return '' if resource.errors.empty? 6 | 7 | messages = resource.errors.full_messages.map do |msg| 8 | content_tag(:li, msg) 9 | end.join 10 | html = <<-HTML 11 |
13 | #{messages} 14 |
15 | HTML 16 | 17 | html.html_safe 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /app/helpers/view_builder_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ViewBuilderHelper 4 | def status_options 5 | [ 6 | ['Pending', 'pending', { class: 'select-pending' }], 7 | ['Active', 'active', { class: 'select-active' }], 8 | ['Deactivated', 'deactivated', { class: 'select-deactivated' }] 9 | ] 10 | end 11 | 12 | def display_border?(container) 13 | container.empty? ? 'layout-placeholder--border' : '' 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/app/lib/assets/.keep -------------------------------------------------------------------------------- /app/lib/catch_error_from_rack.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rack' 4 | 5 | class CatchErrorFromRack 6 | def initialize(app) 7 | @app = app 8 | end 9 | 10 | def call(env) 11 | status, headers, body = @app.call(env) 12 | [status, headers, body] 13 | rescue ActiveRecord::ConnectionNotEstablished 14 | ActiveRecord::Base.establish_connection 15 | status, headers, body = @app.call(env) 16 | [status, headers, body] 17 | rescue ActionController::BadRequest 18 | [301, { 'Location' => get_hostname(env) }, []] 19 | end 20 | 21 | def get_hostname(env) 22 | "#{env['SERVER_NAME']}:#{env['SERVER_PORT']}" 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /app/lib/kuwinda/database_adapter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Kuwinda 4 | class DatabaseAdapter 5 | class << self 6 | def adapter(scheme) 7 | case scheme 8 | when 'postgresql', 'postgres' 9 | 'postgresql' 10 | when 'mysql', 'mysql2' 11 | 'mysql2' 12 | else 13 | raise InvalidClientDatabaseError.new("Do not know how to make adpater for #{scheme}") 14 | end 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/lib/kuwinda/presenter/list_table_fields.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Kuwinda 4 | module Presenter 5 | class ListTableFields 6 | def initialize(database, table) 7 | @database = database 8 | @table = table 9 | end 10 | 11 | def call 12 | Rails.cache.fetch("table_fields/#{database.database.friendly_name}/#{table}", expires_in: 12.hours) do 13 | fields = database.connect.connection.columns(table.downcase).map(&:name) 14 | ActiveRecord::Base.connection_pool.disconnect! if ActiveRecord::Base.connection_pool 15 | ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first) 16 | 17 | fields 18 | end 19 | end 20 | 21 | private 22 | 23 | attr_reader :database, :table 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /app/lib/kuwinda/use_case/database_connection.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Kuwinda 4 | module UseCase 5 | class DatabaseConnection 6 | def initialize(database) 7 | @database = database 8 | @gateway = database_connection_gateway 9 | end 10 | 11 | def execute 12 | gateway 13 | end 14 | 15 | private 16 | 17 | attr_reader :gateway, :database 18 | 19 | def database_connection_gateway 20 | Kuwinda::Gateway::DatabaseConnectionGateway.new(database) 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /app/lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/app/lib/tasks/.keep -------------------------------------------------------------------------------- /app/lib/tasks/assets.rake: -------------------------------------------------------------------------------- 1 | require 'sprockets/rails/task' 2 | 3 | Sprockets::Rails::Task.new(Rails.application) do |t| 4 | t.logger = Logger.new(STDOUT) 5 | end -------------------------------------------------------------------------------- /app/lib/tasks/setup_staging_org_and_roles.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | namespace :setup_org_and_roles do 4 | desc 'setup org' 5 | task setup_all: :environment do 6 | OrganisationSetting.create!( 7 | license_key: 'wcCXJZ5fd3TdekwrB5No912UO2-26', 8 | activation_id: '1559143878', 9 | full_license: false, 10 | company_name: 'Kuwinda Test' 11 | ) 12 | create_admin 13 | create_roles('Sales') 14 | create_roles('Team Lead') 15 | end 16 | end 17 | 18 | def create_admin 19 | Role.create!( 20 | name: 'Admin', 21 | administrator: true, 22 | editor: true, 23 | export: true, 24 | export_limit: 0 25 | ) 26 | end 27 | 28 | def create_roles(role) 29 | Role.create!( 30 | name: role, 31 | administrator: false, 32 | editor: false, 33 | export: false, 34 | export_limit: nil 35 | ) 36 | end 37 | -------------------------------------------------------------------------------- /app/lib/twilio/capability.rb: -------------------------------------------------------------------------------- 1 | module Twilio 2 | class Capability 3 | def self.generate(user) 4 | account_sid = user.twilio_account_sid 5 | auth_token = user.twilio_auth_token 6 | application_sid = user.twilio_application_sid 7 | role = user.role 8 | 9 | capability = Twilio::JWT::ClientCapability.new(account_sid, auth_token) 10 | 11 | outgoing_scope = Twilio::JWT::ClientCapability::OutgoingClientScope.new(application_sid, role) 12 | capability.add_scope outgoing_scope 13 | 14 | capability.to_s 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/app/mailers/.keep -------------------------------------------------------------------------------- /app/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/app/models/.keep -------------------------------------------------------------------------------- /app/models/ability.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Ability 4 | include CanCan::Ability 5 | 6 | def initialize(user); end 7 | 8 | def can?(user, action, subject_class, subject_id) 9 | roles = user.roles.map do |role| 10 | role.permissions.where(action: action).any? do |permission| 11 | permission.subject_class == subject_class.to_s && permission.subject_id == subject_id 12 | end 13 | end 14 | roles.any? true 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/models/activity.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Activity < ApplicationRecord 4 | KINDS = %w[note call meeting outcome].freeze 5 | ## TODO: Figure out the feedable_types based on database? 6 | # FEEDABLE_TYPES = Kuwinda::Presenter::ListAvailableTables.new(@database_connection).call 7 | 8 | validates :content, presence: true 9 | validates :kind, presence: true, inclusion: { in: KINDS } 10 | validates :feedable_id, presence: true 11 | 12 | belongs_to :admin_user, class_name: 'AdminUser', foreign_key: 'user_id' 13 | # validates :feedable_type, presence: true, inclusion: { in: FEEDABLE_TYPES } 14 | end 15 | -------------------------------------------------------------------------------- /app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationRecord < ActiveRecord::Base 4 | self.abstract_class = true 5 | establish_connection Rails.env.to_sym 6 | end 7 | -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/app/models/concerns/.keep -------------------------------------------------------------------------------- /app/models/concerns/client_record.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ClientRecord < ActiveRecord::Base 4 | # self.abstract_class = true 5 | # Kuwinda::UseCase::DatabaseConnection.new.execute 6 | end 7 | -------------------------------------------------------------------------------- /app/models/concerns/database_connection.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DatabaseConnection 4 | def self.reconnect_to_database 5 | ActiveRecord::Base.connection_pool.disconnect! if ActiveRecord::Base.connection_pool 6 | ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first) 7 | "reconnected" if ActiveRecord::Base.connection.active? 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/models/data_table_state.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class DataTableState < ApplicationRecord 4 | def state_as_json 5 | columns = [] 6 | 7 | state['columns'].each do |_k, v| 8 | val = {} 9 | val['visible'] = ActiveModel::Type::Boolean.new.cast(v['visible']) 10 | val['search'] = v['search'] 11 | columns << val 12 | end 13 | 14 | { 15 | time: state['time'].to_i, 16 | start: state['start'].to_i, 17 | length: state['length'].to_i, 18 | order: state['order'], 19 | search: state['search'], 20 | columns: columns 21 | } 22 | end 23 | 24 | def visible_columns 25 | visible_columns = [] 26 | 27 | state['columns'].each do |key, value| 28 | visible_columns << key if value['visible'] == 'true' 29 | end 30 | 31 | visible_columns 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /app/models/database.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Database < ApplicationRecord 4 | include DatabaseActions 5 | before_save :encrypt_database_password 6 | 7 | DATABASE_TYPES = [ 8 | ['PostgreSQL', 'postgresql'], 9 | ['MySQL', 'mysql2'] 10 | ].freeze 11 | 12 | private 13 | 14 | def encrypt_database_password 15 | crypt = ActiveSupport::MessageEncryptor.new(Rails.application.secrets.secret_key_base[0..31]) 16 | password = self.password 17 | crypt.decrypt_and_verify(password) 18 | rescue ActiveSupport::MessageVerifier::InvalidSignature 19 | encrypted_data = crypt.encrypt_and_sign(password) 20 | self.password = encrypted_data 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /app/models/layout_setting.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class LayoutSetting < ApplicationRecord 4 | end 5 | -------------------------------------------------------------------------------- /app/models/permission.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Permission < ApplicationRecord 4 | # has_and_belongs_to_many :roles, join_table: :roles_permissions 5 | has_many :roles 6 | end 7 | -------------------------------------------------------------------------------- /app/models/role.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Role < ApplicationRecord 4 | # has_and_belongs_to_many :admin_users, join_table: :admin_users_roles 5 | has_and_belongs_to_many :permissions, join_table: :roles_permissions 6 | has_many :admin_users 7 | 8 | belongs_to :resource, 9 | polymorphic: true, 10 | optional: true 11 | 12 | validates :resource_type, 13 | inclusion: { in: Rolify.resource_types }, 14 | allow_nil: true 15 | 16 | scopify 17 | 18 | def setting(setting_name) 19 | case setting_name 20 | when 'administrator' 21 | administrator? ? false : true 22 | when 'editor' 23 | editor? ? false : true 24 | when 'export' 25 | export? ? false : true 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /app/models/sql_filter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'sql_filter/equal' 4 | 5 | module SQLFilter 6 | QUERY_CONDITIONS = [ 7 | 'equal' 8 | ].freeze 9 | end 10 | -------------------------------------------------------------------------------- /app/models/sql_filter/base.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SQLFilter 4 | class Base 5 | attr_accessor :kind, 6 | :column, 7 | :value, 8 | :operator 9 | 10 | def initialize(args = {}) 11 | self.kind = args[:kind] 12 | self.column = args[:column] 13 | self.value = args[:value] 14 | self.operator = args[:operator] 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/models/sql_filter/equal.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SQLFilter 4 | class Equal < SQLFilter::Base 5 | def initialize(args = {}) 6 | args[:kind] = 'equal' 7 | super(args) 8 | end 9 | 10 | def to_sql 11 | if operator 12 | "#{operator} #{column} = '#{value}' " 13 | else 14 | "where #{column} = '#{value}' " 15 | end 16 | end 17 | 18 | def to_hash 19 | hash = {} 20 | hash['kind'] = kind 21 | hash['column'] = column 22 | hash['operator'] = operator 23 | hash['value'] = value 24 | hash 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /app/models/sql_filter_factory.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class SQLFilterFactory 4 | def self.build_sql_filter(filter_attributes) 5 | case filter_attributes['kind'] 6 | when 'equal' 7 | build_equal_sql_filter(filter_attributes) 8 | end 9 | end 10 | 11 | def self.build_equal_sql_filter(filter_attributes) 12 | filter = SQLFilter::Equal.new 13 | filter.column = filter_attributes['column'] 14 | filter.value = filter_attributes['value'] 15 | filter.operator = filter_attributes['operator'] 16 | filter 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/models/target_table_setting.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class TargetTableSetting < ApplicationRecord 4 | def create_editable_fields(columns) 5 | columns.map do |column| 6 | add_column_to_editable_fields(column) 7 | end 8 | end 9 | 10 | def update_editable_fields(columns) 11 | columns.map do |column| 12 | next if editable_fields[column.name.to_s] 13 | 14 | add_column_to_editable_fields(column) 15 | end 16 | 17 | remove_stale_columns(columns) 18 | save! 19 | end 20 | 21 | def update_primary_keys(table_primary_keys) 22 | self.primary_keys = {} 23 | self.primary_keys = { 'primary_keys' => table_primary_keys } 24 | save! 25 | end 26 | 27 | private 28 | 29 | def add_column_to_editable_fields(column) 30 | self.editable_fields = {} if editable_fields.nil? 31 | editable_fields.merge!(column.name.to_s => { 'editable' => false, 'mandatory' => false }) 32 | end 33 | 34 | def remove_stale_columns(columns) 35 | column_names = columns.map(&:name) 36 | editable_fields.delete_if { |key, _value| !column_names.include? key } 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /app/models/task_queue.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class TaskQueue < ApplicationRecord 4 | validates :name, :table, presence: true 5 | has_many :task_queue_outcomes 6 | 7 | scope :enabled, -> { where(enabled: true) } 8 | 9 | def success_outcome_enabled? 10 | success_database_update['enabled'] ? true : false 11 | end 12 | 13 | def failure_outcome_enabled? 14 | failure_database_update['enabled'] ? true : false 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/models/task_queue_outcome.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class TaskQueueOutcome < ApplicationRecord 4 | OUTCOMES = %w[ 5 | success 6 | failure 7 | ].freeze 8 | 9 | belongs_to :task_queue 10 | validates :outcome, inclusion: { in: OUTCOMES } 11 | validates :outcome, 12 | :task_queue_id, 13 | :task_queue_item_table, 14 | :task_queue_item_primary_key, presence: true 15 | end 16 | -------------------------------------------------------------------------------- /app/models/view_builder.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ViewBuilder < ApplicationRecord 4 | validates :table_name, presence: true 5 | validates :table_name, uniqueness: { scope: :database_id } 6 | 7 | def table_headers 8 | table_attributes['visible_fields'].map { |_k, field| field } 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/models/work_list_outcome.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class WorkListOutcome 4 | attr_accessor :title, 5 | :detail 6 | 7 | def initialize(args = {}) 8 | self.title = args['title'] || '' 9 | self.detail = args['detail'] || '' 10 | end 11 | 12 | def to_hash 13 | hash = {} 14 | hash['title'] = title 15 | hash['detail'] = detail 16 | hash 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/services/verify_license_key_service.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class VerifyLicenseKeyService 4 | class << self 5 | include HTTParty 6 | 7 | STATUS = { sold: '1', delivered: '2', active: '3', inactive: '4' }.freeze 8 | 9 | def verify(license_key) 10 | response = call("/#{license_key}") 11 | return true if response['data']['status'] == STATUS[:active] 12 | 13 | activate(license_key) 14 | end 15 | 16 | def activate(license_key) 17 | response = call("/activate/#{license_key}") 18 | response.code == 200 19 | end 20 | 21 | private 22 | 23 | def call(endpoint); end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /app/views/activities/_activity.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%= activity.created_at.strftime('%a, %d %b %Y at %I:%M') %> 4 | 5 | 6 | <%= render_activity(activity) %> 7 | <% if locals[:link] %> 8 | to a <%= link_to "record", table_record_preview_path(table: activity.feedable_type, table_name: activity.feedable_type, record_id: activity.feedable_id, database_id: activity.database_id) %> on <%= link_to activity.feedable_type, table_path(id: activity.database_id, table: activity.feedable_type) %> table 9 | <% end %> 10 | 11 | -------------------------------------------------------------------------------- /app/views/activities/_form.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= form_with(model: @activity, local: false, data: { 'activity-form' => true }, class: 'activity-comment-form') do |form| %> 3 | <%= form.hidden_field :feedable_type, id: :feedable_type, value: feedable_type %> 4 | <%= form.hidden_field :feedable_id, id: :feedable_id, value: feedable_id %> 5 | <%= form.hidden_field :database_id, value: @database.id %> 6 | <%= form.hidden_field :kind, value: 'note' %> 7 | <%= form.hidden_field :user_id, value: current_admin_user.id %> 8 | 9 | 10 | <%= form.text_field :content, placeholder: 'Click to add a comment', class: "activity-comment-form--input" %> 11 | <%= form.submit 'Submit', class: 'btn btn-info btn-middle-align btn-square' %> 12 | <% end %> 13 |
14 | -------------------------------------------------------------------------------- /app/views/activities/_task_queue_record_activity_form.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= form_with(model: @activity, local: false, scope: 'activity', html: { id: 'task-queue-record-activity-form' }, url: activities_path) do |form| %> 3 |
4 | <%= form.text_area :content, class: "form-control" %> 5 |
6 | 7 |
8 | <%= form.hidden_field :feedable_type, id: :feedable_type, value: feedable_type %> 9 | <%= form.hidden_field :kind, value: 'note' %> 10 |
11 | 12 |
13 |
14 |
15 | <%= form.submit 'Save', class: 'btn btn-primary', id: 'task-queue-record-activity-submit' %> 16 |
17 |
18 |
19 | <% end %> 20 |
21 | -------------------------------------------------------------------------------- /app/views/activities/failure.js.erb: -------------------------------------------------------------------------------- 1 | toastr.error('Failed to save activity.'); 2 | -------------------------------------------------------------------------------- /app/views/activities/index.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Activity history

4 | 5 | 14 |
15 |
16 | 17 |
18 |
19 |
20 | <%= render 'shared/activity_history', feedable_type: @feedable_type, feedable_id: @feedable_id, index: true %> 21 |
22 |
23 |
-------------------------------------------------------------------------------- /app/views/admin_users/_new_modal.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 7 |
-------------------------------------------------------------------------------- /app/views/admin_users/_permissions.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
-------------------------------------------------------------------------------- /app/views/admin_users/_roles.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | <% @roles.each do |role| %> 14 | 15 | 16 | 17 | 18 | 19 | <% end %> 20 | 21 |
IDNameActions
<%= role.id %><%= role.name %>action buttons
22 |
23 |
24 |
-------------------------------------------------------------------------------- /app/views/admin_users/_status.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
STATUS
4 |
5 |
6 | 7 | <% @admin_user_statuses.each do |status, users_count| %> 8 | 9 | 12 | 15 | 16 | <% end %> 17 |
10 | <%= status.capitalize %> 11 | 13 | <%= pluralize users_count, "user" %> 14 |
18 |
19 |
-------------------------------------------------------------------------------- /app/views/admin_users/_teams.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
TEAMS
4 |
Add
5 |
6 |
7 | 8 | <% @admin_user_roles.sort.each do |role, users_count| %> 9 | 10 | 13 | 19 | 20 | <% end %> 21 |
11 | <%= role %> 12 | 14 |
15 | <%= pluralize users_count, "user" %> 16 |
17 | Edit 18 |
22 |
23 |
24 | -------------------------------------------------------------------------------- /app/views/admin_users/_users_table.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= render partial: "shared/table_filter_bar.html.erb", locals: { users: true } %> 3 |
4 |
5 |

Users

6 | 7 | 8 | 9 | <% @headers.each do |header|%> 10 | 11 | <% end %> 12 | 13 | 14 |
<%= header.humanize %>
15 |
16 |
17 |
-------------------------------------------------------------------------------- /app/views/admin_users/create_new.js.erb: -------------------------------------------------------------------------------- 1 | <% if @result %> 2 | toastr.success('New user has been successfully created.'); 3 | $('#users--team-partial').html("<%= j render("teams")%>"); 4 | $('#users--status-partial').html("<%= j render("status")%>"); 5 | $("#target-table-admin-users").DataTable().ajax.reload(); 6 | $('.users--new-modal').removeClass('show'); 7 | $('.users--new-modal').addClass('hide'); 8 | <% else %> 9 | toastr.error('Unable to save new user. Please check email is not already in use.'); 10 | <% end %> -------------------------------------------------------------------------------- /app/views/admin_users/delete_failure.js.erb: -------------------------------------------------------------------------------- 1 | toastr.error('You cannot delete the last admin user, or yourself. Please make sure there is another admin user set up first.'); -------------------------------------------------------------------------------- /app/views/admin_users/destroy.js.erb: -------------------------------------------------------------------------------- 1 | toastr.success('User has been successfully deleted.'); 2 | $('#users--team-partial').html("<%= j render("teams")%>"); 3 | $('#users--status-partial').html("<%= j render("status")%>"); 4 | $("#target-table-admin-users").DataTable().ajax.reload(); 5 | $('.users--edit-modal').removeClass('show'); 6 | $('.users--edit-modal').addClass('hide'); -------------------------------------------------------------------------------- /app/views/admin_users/edit.js.erb: -------------------------------------------------------------------------------- 1 | $('.modal--content-container').html("<%= j render('user_form') %>"); 2 | -------------------------------------------------------------------------------- /app/views/admin_users/index.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :head do %> 2 | <%= javascript_include_tag 'dataTable/datatables.min.js' %> 3 | <% end %> 4 | 5 | <%= render 'shared/page_banner_header', title: 'Settings', items: ['Settings', 'Users'] %> 6 | 7 |
8 |
9 |
10 |
11 |
12 | <%= render partial: 'teams' %> 13 |
14 |
15 | <%= render partial: 'status' %> 16 |
17 |
18 |
19 |
20 |
21 |
22 | <%= render partial: 'users_table' %> 23 |
24 |
25 |
26 |
27 |
28 | 29 |
30 | 31 |
32 | 33 |
34 | -------------------------------------------------------------------------------- /app/views/admin_users/new.js.erb: -------------------------------------------------------------------------------- 1 | $('#users--new-modal').html("<%= j render("new_modal")%>") 2 | $('.users--new-modal').removeClass('hide'); 3 | $('.users--new-modal').addClass('show'); -------------------------------------------------------------------------------- /app/views/admin_users/show_modal.js.erb: -------------------------------------------------------------------------------- 1 | $('#users--edit-modal').html("<%= j render("show_modal")%>") 2 | $('.users--edit-modal').removeClass('hide'); 3 | $('.users--edit-modal').addClass('show'); -------------------------------------------------------------------------------- /app/views/admin_users/update.js.erb: -------------------------------------------------------------------------------- 1 | <% if @result %> 2 | toastr.success('User has been successfully updated.'); 3 | $('#users--team-partial').html("<%= j render("teams")%>"); 4 | $('#users--status-partial').html("<%= j render("status")%>"); 5 | var table = $("#target-table-admin-users").DataTable() 6 | table.ajax.reload(); 7 | filterByTeams(table); 8 | filterByStatus(table); 9 | clearFilters(table); 10 | $('.users--edit-modal').removeClass('show'); 11 | $('.users--edit-modal').addClass('hide'); 12 | <% else %> 13 | toastr.error('Unable to update user. Please check email is not already in use.'); 14 | <% end %> -------------------------------------------------------------------------------- /app/views/admin_users/update_role.js.erb: -------------------------------------------------------------------------------- 1 | toastr.success('Team has been successfully updated.'); 2 | $('#users--team-partial').html("<%= j render("teams")%>"); 3 | var table = $("#target-table-admin-users").DataTable() 4 | table.ajax.reload(); 5 | filterByTeams(table); 6 | filterByStatus(table); 7 | clearFilters(table); -------------------------------------------------------------------------------- /app/views/admin_users/update_status.js.erb: -------------------------------------------------------------------------------- 1 | toastr.success('Status has been successfully updated.'); 2 | $('#users--status-partial').html("<%= j render("status")%>"); 3 | var table = $("#target-table-admin-users").DataTable() 4 | table.ajax.reload(); 5 | filterByTeams(table); 6 | filterByStatus(table); 7 | clearFilters(table); -------------------------------------------------------------------------------- /app/views/dashboard/_license_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_tag("/license/verify", method: "post") do %> 2 |
3 | <%= label_tag(:license_key, "License key") %> 4 | <%= text_field_tag(:license_key, '', {class: 'form-control', required: true}) %> 5 |
6 | 7 |

8 | If this was a trial license you will need to buy a license here. 9 |

10 | 11 | <%= submit_tag("Submit", {class: 'btn btn-primary'}) %> 12 | <% end %> 13 | -------------------------------------------------------------------------------- /app/views/dashboard/license.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 9 | 10 | 11 |
12 |
13 | 14 |

Welcome

15 | 16 |
17 | 18 |

Welcome to the installation process. You’ll need a license key to get set-up. You can get a trial or full license key from www.missionkontrol.io

19 | 20 | <%= render 'license_form' %> 21 | 22 |

23 | Server response: License terminated. If this is unexpected please contact team@missionkontrol.io 24 |

25 |
26 |
27 |
28 |
29 |
30 | -------------------------------------------------------------------------------- /app/views/dashboard/verify_license.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 9 | 10 | 11 |
12 |
13 | 14 |

License invalid

15 | 16 |
17 | 18 |

You’ll need a valid license key to continue. If this is unexpected please contact team@missionkontrol.io

19 | 20 | <%= render 'license_form' %> 21 |
22 |
23 |
24 |
25 |
26 | -------------------------------------------------------------------------------- /app/views/databases/create.js.erb: -------------------------------------------------------------------------------- 1 | <% if @result %> 2 | window.location.assign('/permissions'); 3 | toastr.success('Database has been successfully created.') 4 | <% else %> 5 | toastr.error('Unable to save database. Please check your credentials and try again.'); 6 | <% end %> -------------------------------------------------------------------------------- /app/views/databases/edit.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'shared/page_banner_header', title: 'Settings', items: ['Settings', 'Databases', "#{@database.friendly_name}"] %> 2 | 3 | <%= render 'tabs' %> -------------------------------------------------------------------------------- /app/views/databases/new.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'shared/page_banner_header', title: 'Settings', items: ['Settings', 'Databases'] %> 2 | 3 | <%= render 'tabs' %> -------------------------------------------------------------------------------- /app/views/databases/test_connection.js.erb: -------------------------------------------------------------------------------- 1 | <% if @active_connection %> 2 | toastr.success('Database connection successful.') 3 | <% else %> 4 | toastr.error('Unable to connect to database. Please check your credentials and try again.'); 5 | <% end %> -------------------------------------------------------------------------------- /app/views/databases/test_gem.js.erb: -------------------------------------------------------------------------------- 1 | <% if @active_gem_connection %> 2 | toastr.success('Gem connection successful.') 3 | <% else %> 4 | toastr.error('Unable to connect to your application. Please check your credentials and try again.'); 5 | <% end %> -------------------------------------------------------------------------------- /app/views/databases/update.js.erb: -------------------------------------------------------------------------------- 1 | <% if @result %> 2 | toastr.success("<%= t('successes.has_been_successfully_updated', model: 'Database') %>"); 3 | <% else %> 4 | toastr.error("<%= t('errors.unable_to_save', model: 'database') %>"); 5 | <% end %> -------------------------------------------------------------------------------- /app/views/devise/confirmations/new.html.erb: -------------------------------------------------------------------------------- 1 |

Resend confirmation instructions

2 | 3 | <%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %> 4 | <%= devise_error_messages! %> 5 | 6 |
7 | <%= f.label :email %>
8 | <%= f.email_field :email, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %> 9 |
10 | 11 |
12 | <%= f.submit "Resend confirmation instructions" %> 13 |
14 | <% end %> 15 | 16 | <%= render "devise/shared/links" %> 17 | -------------------------------------------------------------------------------- /app/views/devise/mailer/confirmation_instructions.html.erb: -------------------------------------------------------------------------------- 1 |

Welcome <%= @email %>!

2 | 3 |

You can confirm your account email through the link below:

4 | 5 |

<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>

6 | -------------------------------------------------------------------------------- /app/views/devise/mailer/email_changed.html.erb: -------------------------------------------------------------------------------- 1 |

Hello <%= @email %>!

2 | 3 | <% if @resource.try(:unconfirmed_email?) %> 4 |

We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.

5 | <% else %> 6 |

We're contacting you to notify you that your email has been changed to <%= @resource.email %>.

7 | <% end %> 8 | -------------------------------------------------------------------------------- /app/views/devise/mailer/password_change.html.erb: -------------------------------------------------------------------------------- 1 |

Hello <%= @resource.email %>!

2 | 3 |

We're contacting you to notify you that your password has been changed.

4 | -------------------------------------------------------------------------------- /app/views/devise/mailer/reset_password_instructions.html.erb: -------------------------------------------------------------------------------- 1 |

Hello <%= @resource.email %>!

2 | 3 |

Someone has requested a link to change your password. You can do this through the link below.

4 | 5 |

<%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %>

6 | 7 |

If you didn't request this, please ignore this email.

8 |

Your password won't change until you access the link above and create a new one.

9 | -------------------------------------------------------------------------------- /app/views/devise/mailer/unlock_instructions.html.erb: -------------------------------------------------------------------------------- 1 |

Hello <%= @resource.email %>!

2 | 3 |

Your account has been locked due to an excessive number of unsuccessful sign in attempts.

4 | 5 |

Click the link below to unlock your account:

6 | 7 |

<%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>

8 | -------------------------------------------------------------------------------- /app/views/devise/passwords/edit.html.erb: -------------------------------------------------------------------------------- 1 |

Change your password

2 | 3 | <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %> 4 | <%= devise_error_messages! %> 5 | <%= f.hidden_field :reset_password_token %> 6 | 7 |
8 | <%= f.label :password, "New password" %>
9 | <% if @minimum_password_length %> 10 | (<%= @minimum_password_length %> characters minimum)
11 | <% end %> 12 | <%= f.password_field :password, autofocus: true, autocomplete: "off" %> 13 |
14 | 15 |
16 | <%= f.label :password_confirmation, "Confirm new password" %>
17 | <%= f.password_field :password_confirmation, autocomplete: "off" %> 18 |
19 | 20 |
21 | <%= f.submit "Change my password" %> 22 |
23 | <% end %> 24 | 25 | <%= render "devise/shared/links" %> 26 | -------------------------------------------------------------------------------- /app/views/devise/passwords/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 |
7 |
8 | 9 |

Forgot your password?

10 | 11 | <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %> 12 | <%= devise_error_messages! %> 13 | 14 |
15 | <%= f.label :email, "Email" %>
16 | <%= f.email_field :email, autofocus: true, autocomplete: "email", class: 'form-control', required: true %> 17 |
18 | 19 |
20 | <%= f.submit "Send me reset password instructions", class: 'btn btn-primary block full-width m-b' %> 21 |
22 | <% end %> 23 | 24 | <%- if controller_name != 'sessions' %> 25 | 26 | <%= link_to "Log in", new_session_path(resource_name) %>
27 |
28 | <% end -%> 29 |
30 |
31 | -------------------------------------------------------------------------------- /app/views/devise/registrations/_form_content.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'registration_form_one', f: f %> -------------------------------------------------------------------------------- /app/views/devise/registrations/edit.js.erb: -------------------------------------------------------------------------------- 1 | $('#users--modal').html("<%= j render("/admin_users/edit_modal")%>") 2 | $('.users--edit-modal').removeClass('hide'); 3 | $('.users--edit-modal').addClass('show'); -------------------------------------------------------------------------------- /app/views/devise/registrations/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: {class: "m-t"}) do |f| %> 5 | <%= devise_error_messages! %> 6 | 7 | <%= render 'form_content', f: f %> 8 | <% end %> 9 |
10 |
11 |
12 | -------------------------------------------------------------------------------- /app/views/devise/unlocks/new.html.erb: -------------------------------------------------------------------------------- 1 |

Resend unlock instructions

2 | 3 | <%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %> 4 | <%= devise_error_messages! %> 5 | 6 |
7 | <%= f.label :email %>
8 | <%= f.email_field :email, autofocus: true, autocomplete: "email" %> 9 |
10 | 11 |
12 | <%= f.submit "Resend unlock instructions" %> 13 |
14 | <% end %> 15 | 16 | <%= render "devise/shared/links" %> 17 | -------------------------------------------------------------------------------- /app/views/errors/internal_server_error.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Oh no! Something seems to have gone wrong!

5 |
6 |

Try reload the page or visit the <%= link_to 'dashboard', dashboard_path %>.

7 |
8 |

If that fails please speak to a system administrator.

9 |
10 |
11 |
-------------------------------------------------------------------------------- /app/views/errors/internal_server_error.js.erb: -------------------------------------------------------------------------------- 1 | toastr.error("There appears to be an error with the application. Please reload or speak to an Administrator"); 2 | -------------------------------------------------------------------------------- /app/views/errors/not_acceptable.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Oh no! Something seems to have gone wrong!

5 |
6 |

Try reload the page or visit the <%= link_to 'dashboard', dashboard_path %>.

7 |
8 |

If that fails please speak to a system administrator.

9 |
10 |
11 |
-------------------------------------------------------------------------------- /app/views/errors/not_acceptable.js.erb: -------------------------------------------------------------------------------- 1 | toastr.error("There appears to be an error with the application. Please reload or speak to an Administrator"); 2 | -------------------------------------------------------------------------------- /app/views/errors/not_authorized.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Oh no! You're trying to access something you don't have permissions to access!

5 |
6 |

Please speak to a system administrator if you believe this to be wrong.

7 |
8 |
9 |
-------------------------------------------------------------------------------- /app/views/errors/not_authorized.js.erb: -------------------------------------------------------------------------------- 1 | toastr.error("You're trying to access something you don't have permissions to access."); 2 | -------------------------------------------------------------------------------- /app/views/errors/not_found.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Oh no! We seem to have lost connection to your database!

5 |
6 |

This could be due to a few simple things. Let's run through a few simple things to check before you really start panicking...

7 |
    8 |
  • Did you just change your database settings? Could you have typed the password wrong?
  • 9 |
  • Has someone changed a firewall surrounding your database so MissionKontrol can no longer see it?
  • 10 |
  • Is your database still connected to the internet?
  • 11 |
  • Is your database even still alive?
  • 12 |
  • ...
  • 13 |
  • Ok maybe you can start panicking now
  • 14 |
      15 |
      16 |

      Check your settings or speak to a system administrator.

      17 |
18 |
19 |
-------------------------------------------------------------------------------- /app/views/errors/not_found.js.erb: -------------------------------------------------------------------------------- 1 | toastr.error("There appears to be an error with your database connection. Please check your credentials or speak to an Administrator"); 2 | -------------------------------------------------------------------------------- /app/views/home/index.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Welcome to MissionKontrol

5 | 6 |
7 | <%= link_to 'Register', new_admin_user_registration_path %> | 8 | <%= link_to 'Dashboard', dashboard_path %> 9 |
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /app/views/layout_builder/_field_settings_form_old.html.erb: -------------------------------------------------------------------------------- 1 | <% @action_for_layout_builder = action_name == 'edit' ? 'update' : 'create' %> 2 | <%= form_for @view_builder, :url => url_for(:controller => 'layout_builder', action: @action_for_layout_builder), remote: true, html: {class: 'hide'} do |form| %> 3 |
4 | <%= form.hidden_field :layout_id, value: params[:id] %> 5 |
6 | 7 |
8 |

Select the fields that will be visible for this layout.

9 | 10 | <%= select_tag 'layout_setting[visible_columns][]', 11 | '', 12 | multiple: true, 13 | include_blank: false, 14 | prompt: "", 15 | data: { columns: @layout_setting.visible_columns.to_json }, 16 | id: "layout_setting_visible_columns" %> 17 |
18 | 19 |
20 | <%= form.submit "Save", class: "btn btn-primary" %> 21 |
22 | <% end %> 23 | -------------------------------------------------------------------------------- /app/views/layout_builder/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :head do %> 2 | <%= javascript_include_tag 'dragula/dragula.min.js' %> 3 | <%= javascript_include_tag 'shopify/draggable.bundle.js' %> 4 | <%= javascript_include_tag 'sweetAlert/sweetalert.min.js' %> 5 | <% end %> 6 | 7 |
8 | <%= @database.id %> 9 |
10 | 11 | 16 | 17 |
18 |
19 |
20 | <%= link_to "Preview", table_record_preview_path(table: @view_builder.table_name, table_name: @view_builder.table_name.downcase, record_id: @row, database_id: @database.id) %> 21 |
22 |
23 |
24 | 25 |
26 | <%= render 'layout_builder/initial_placeholder' %> 27 |
28 | -------------------------------------------------------------------------------- /app/views/layout_builder/edit/error.js.erb: -------------------------------------------------------------------------------- 1 | toastr.error("Invalid target database, please review credentials.") 2 | -------------------------------------------------------------------------------- /app/views/layout_builder/edit/success.js.erb: -------------------------------------------------------------------------------- 1 | let layoutId = window.location.pathname.split("/")[2]; 2 | window.location.href = window.location.origin + "/layouts/" + layoutId + "/preview" 3 | -------------------------------------------------------------------------------- /app/views/layout_builder/new.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :head do %> 2 | <%= javascript_include_tag 'dragula/dragula.min.js' %> 3 | <%= javascript_include_tag 'shopify/draggable.bundle.js' %> 4 | <%= javascript_include_tag 'shopify/sortable.js' %> 5 | <% end %> 6 | 7 | 17 | 18 |
19 | <%= render 'layout_builder/initial_placeholder' %> 20 |
21 | -------------------------------------------------------------------------------- /app/views/layout_builder/select_table_fields.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 | 5 |
6 |
7 | 8 |
9 |
10 | -------------------------------------------------------------------------------- /app/views/layout_builder/update/success.js: -------------------------------------------------------------------------------- 1 | toastr.options = { 2 | closeButton: true, 3 | showMethod: "fadeIn", 4 | hideMethod: "fadeOut", 5 | timeOut: 5000, 6 | preventDuplicates: true, 7 | positionClass: "toast-bottom-right" 8 | }; 9 | 10 | toastr.info("Layout successfully updated."); 11 | -------------------------------------------------------------------------------- /app/views/layouts/_footer.html.erb: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /app/views/layouts/_mouseflow.html.erb: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /app/views/layouts/_natterly.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/views/layouts/_topnavbar.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 4 |
5 | -------------------------------------------------------------------------------- /app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MissionKontrol 5 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> 6 | <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> 7 | <%= csrf_meta_tags %> 8 | <%= favicon_link_tag 'favicon.ico' %> 9 | <%= yield(:head) %> 10 | 11 | 12 | 13 |
14 | <%= render 'shared/flash_message' %> 15 | <%= yield %> 16 | <%= insert_paloma_hook %> 17 |
18 | 19 |
20 | 21 | <%= render 'layouts/natterly' %> 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/views/layouts/bad_connection.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Oh no! We seem to have lost connection to your database!

5 |
6 |

This could be due to a few simple things. Let's run through a few simple things to check before you really start panicking...

7 |
    8 |
  • Did you just change your database settings? Could you have typed the password wrong?
  • 9 |
  • Has someone changed a firewall surrounding your database so MissionKontrol can no longer see it?
  • 10 |
  • Is your database still connected to the internet?
  • 11 |
  • Is your database even still alive?
  • 12 |
  • ...
  • 13 |
  • Ok maybe you can start panicking now
  • 14 |
      15 |
      16 |

      <%= link_to 'Check your settings here', edit_organisation_setting_path(current_organisation), html_options = { class: "underline" } %> and then refresh the page

      17 |
18 |
19 |
-------------------------------------------------------------------------------- /app/views/layouts/license.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MissionKontrol 5 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> 6 | <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> 7 | <%= csrf_meta_tags %> 8 | <%= favicon_link_tag 'favicon.ico' %> 9 | 10 | 11 | 12 |
13 | <%= yield %> 14 |
15 | 16 |
17 | 18 | <%= render 'layouts/natterly' %> 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/views/organisation_settings/update.js.erb: -------------------------------------------------------------------------------- 1 | <% if @invalid_key %> 2 | toastr.error("<%= t('errors.unable_to_activate_license_key') %>") 3 | <% elsif @result %> 4 | toastr.success("<%= t('successes.have_been_successfully_updated', model: 'Settings') %>"); 5 | <% else %> 6 | toastr.error("<%= t('errors.unable_to_save', model: 'settings') %>"); 7 | <% end %> -------------------------------------------------------------------------------- /app/views/permissions/add_to_role.js.erb: -------------------------------------------------------------------------------- 1 | toastr.success('Settings have been successfully updated.'); 2 | 3 | // $('.data-table-permissions').DataTable().ajax.reload(); -------------------------------------------------------------------------------- /app/views/permissions/disable_all.js.erb: -------------------------------------------------------------------------------- 1 | window["datatable"+<%= @database_id %>].ajax.reload(); 2 | toastr.success('Settings have been successfully updated.'); -------------------------------------------------------------------------------- /app/views/permissions/enable_all.js.erb: -------------------------------------------------------------------------------- 1 | window["datatable"+<%= @database_id %>].ajax.reload(); 2 | toastr.success('Settings have been successfully updated.'); -------------------------------------------------------------------------------- /app/views/permissions/index.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :head do %> 2 | <%= javascript_include_tag 'dataTable/datatables.min.js' %> 3 | <% end %> 4 | 5 | <%= render 'shared/page_banner_header', title: 'Settings', items: ['Settings', 'Permissions'] %> 6 | 7 |
8 |
9 |
10 | <% @databases.each do |database| %> 11 | 12 |
13 | 14 | 15 | 16 | <% @headers.each do |header|%> 17 | 18 | <% end %> 19 | 20 | 21 |
<%= header.humanize %>
22 |
23 | <% end %> 24 |
25 |
26 |
-------------------------------------------------------------------------------- /app/views/permissions/remove_from_role.js.erb: -------------------------------------------------------------------------------- 1 | toastr.success('Settings have been successfully updated.'); 2 | 3 | // $('.data-table-permissions').DataTable().ajax.reload(); -------------------------------------------------------------------------------- /app/views/roles/edit.js.erb: -------------------------------------------------------------------------------- 1 | $('#roles--edit-modal').html("<%= j render("edit_modal")%>") 2 | $('.roles--edit-modal').removeClass('hide'); 3 | $('.roles--edit-modal').addClass('show'); 4 | -------------------------------------------------------------------------------- /app/views/roles/update.js.erb: -------------------------------------------------------------------------------- 1 | toastr.success('Role settings have been successfully updated.'); 2 | -------------------------------------------------------------------------------- /app/views/roles/update_error.js.erb: -------------------------------------------------------------------------------- 1 | toastr.error('Cannot remove administrator permissions from all Teams. Please add administrator permissions to another team before removing here.'); 2 | $('#roles--edit-modal').html("<%= j render("show_modal")%>"); 3 | $('.roles--edit-modal').removeClass('hide'); 4 | $('.roles--edit-modal').addClass('show'); -------------------------------------------------------------------------------- /app/views/shared/_activity_stream.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | <% activities.each do |activity| %> 4 | <%= render 'activities/activity', activity: activity, locals: { link: locals[:link] } %> 5 | <% end %> 6 | 7 |
-------------------------------------------------------------------------------- /app/views/shared/_flash_message.html.erb: -------------------------------------------------------------------------------- 1 | <% flash.each do |key, value| %> 2 |
3 |
4 | × 5 | 10 |
11 | <% end %> 12 | -------------------------------------------------------------------------------- /app/views/shared/_page_banner_header.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |

<%= title %>

4 | 5 | 12 |
13 |
-------------------------------------------------------------------------------- /app/views/tables/_record_summary.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | <% @row.first(5).each do |k, v| %> 6 |

7 | <%= k %>: <%= v %> 8 |

9 | <% end %> 10 |
11 |
12 |
13 |
14 | -------------------------------------------------------------------------------- /app/views/tables/_related_data_table.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |

<%= current_table.humanize %>

4 |
5 | <% table_settings = TargetTableSetting.where(name: current_table, database_id: @database.id).first %> 6 | 7 | 8 | 9 | <% headers.each do |header|%> 10 | 11 | <% end %> 12 | 13 | 14 | 15 |
16 |
17 | -------------------------------------------------------------------------------- /app/views/tables/_related_table_with_layout.html.erb: -------------------------------------------------------------------------------- 1 | <% r.each_with_index do |(k, v), i| %> 2 | <% @column_is_hidden = hidden_columns.include?(k) %> 3 | 4 | <% if @column_is_hidden %> 5 | 6 | <%= render 'table_cell_data', v: v %> 7 | 8 | <% else %> 9 | 10 | <%= render 'table_cell_data', v: v %> 11 | 12 | <% end %> 13 | <% end %> 14 | -------------------------------------------------------------------------------- /app/views/tables/_table_cell_data.html.erb: -------------------------------------------------------------------------------- 1 | <% if v %> 2 | <%= v %> 3 | <% else %> 4 | -- 5 | <% end %> 6 | -------------------------------------------------------------------------------- /app/views/tables/_table_with_layout.html.erb: -------------------------------------------------------------------------------- 1 | <% r.each_with_index do |(k, v), i| %> 2 | <% @column_is_hidden = @hidden_columns.include?(k) %> 3 | 4 | <% if @column_is_hidden %> 5 | 6 | <%= render 'table_cell_data', v: v %> 7 | 8 | <% else %> 9 | 10 | <%= render 'table_cell_data', v: v %> 11 | 12 | <% end %> 13 | <% end %> 14 | -------------------------------------------------------------------------------- /app/views/tables/_table_without_layout.html.erb: -------------------------------------------------------------------------------- 1 | <% r.first(5).each_with_index do |(k, v), i| %> 2 | 3 | <%= render 'table_cell_data', v: v %> 4 | 5 | <% end %> 6 | -------------------------------------------------------------------------------- /app/views/tables/add_record.js.erb: -------------------------------------------------------------------------------- 1 | $('#table--add-record-modal').html("<%= j render("add_record_modal")%>") 2 | $('.table--add-record-modal').removeClass('hide'); 3 | $('.table--add-record-modal').addClass('show'); -------------------------------------------------------------------------------- /app/views/tables/create_record.js.erb: -------------------------------------------------------------------------------- 1 | <% if @error %> 2 | toastr.error("<%= @error_message %>") 3 | <% else %> 4 | toastr.success('Record has been successfully created.'); 5 | $(".data-table").DataTable().ajax.reload(); 6 | $('.table--add-record-modal').removeClass('show'); 7 | $('.table--add-record-modal').addClass('hide'); 8 | <% end %> 9 | -------------------------------------------------------------------------------- /app/views/tables/delete_record.js.erb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/app/views/tables/delete_record.js.erb -------------------------------------------------------------------------------- /app/views/tables/edit_record.js.erb: -------------------------------------------------------------------------------- 1 | <% if @error %> 2 | toastr.error("<%= @error_message %>") 3 | <% else %> 4 | $('#table--edit-record-modal').html("<%= j render("edit_record_modal")%>") 5 | $('.table--edit-record-modal').removeClass('hide'); 6 | $('.table--edit-record-modal').addClass('show'); 7 | <% end %> 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/views/tables/layout/_editable_actions.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
6 | 7 |
8 | 9 | 10 | 11 | 12 | <% if v["table"] == @current_table %> 13 | ', '<%= v["title"] %>', '<%= params[:record_id] %>');"> 14 | 15 | 16 | <% else %> 17 | ', '<%= v["title"] %>', '<%= get_foreign_key(@current_table) %>' ,'<%= params[:record_id] %>');"> 18 | 19 | 20 | <% end %> 21 |
22 | -------------------------------------------------------------------------------- /app/views/tables/layout/_main_container1.html.erb: -------------------------------------------------------------------------------- 1 | <% fields_for_main_container1(layout_builder).each do |index, field| %> 2 | <%= render partial: 'tables/layout/container_content', locals: { field: field } %> 3 | <% end %> 4 | -------------------------------------------------------------------------------- /app/views/tables/layout/_main_container2.html.erb: -------------------------------------------------------------------------------- 1 | <% fields_for_main_container2(layout_builder).each do |index, field| %> 2 | <%= render partial: 'tables/layout/container_content', locals: { field: field } %> 3 | <% end %> 4 | -------------------------------------------------------------------------------- /app/views/tables/layout/_main_container3.html.erb: -------------------------------------------------------------------------------- 1 | <% fields_for_main_container3(layout_builder).each do |index, field| %> 2 | <%= render partial: 'tables/layout/container_content', locals: { field: field } %> 3 | <% end %> 4 | -------------------------------------------------------------------------------- /app/views/tables/settings.js.erb: -------------------------------------------------------------------------------- 1 | $('#table--settings-modal').html("<%= j render("settings_modal")%>") 2 | $('.table--settings-modal').removeClass('hide'); 3 | $('.table--settings-modal').addClass('show'); -------------------------------------------------------------------------------- /app/views/tables/show.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :head do %> 2 | <%= javascript_include_tag 'dataTable/datatables.min.js' %> 3 | <% end %> 4 | 5 | <%= render 'shared/page_banner_header', title: @current_table.capitalize, items: ['Database', @current_table.capitalize] %> 6 | 7 |
8 |
9 |
10 |
11 |
12 |
13 | <%= render 'data_table', current_table: @current_table, table_settings: @current_table_settings %> 14 |
15 |
16 |
17 |
18 |
19 | 20 |
21 | 22 |
23 | 24 |
-------------------------------------------------------------------------------- /app/views/tables/show/failure.js.erb: -------------------------------------------------------------------------------- 1 | toastr.error('Failed to update column settings.'); 2 | -------------------------------------------------------------------------------- /app/views/tables/show/success.js.erb: -------------------------------------------------------------------------------- 1 | toastr.success('Column settings updated.'); 2 | -------------------------------------------------------------------------------- /app/views/tables/update_record.js.erb: -------------------------------------------------------------------------------- 1 | <% if @error %> 2 | toastr.error("<%= @error_message || 'Unable to save the record. Please check all your fields.' %>") 3 | <% else %> 4 | toastr.success('Record(s) has been successfully updated.'); 5 | $(".data-table").DataTable().ajax.reload(); 6 | $(".table--filter-bar").last().remove(); 7 | $('.table--edit-record-modal').removeClass('show'); 8 | $('.table--edit-record-modal').addClass('hide'); 9 | <% end %> 10 | -------------------------------------------------------------------------------- /app/views/tables/update_settings.js.erb: -------------------------------------------------------------------------------- 1 | <% if @result %> 2 | toastr.success('Table settings have been successfully updated.'); 3 | <% if @table_settings.nested_table.nil? %> 4 | $(".data-table").data("nested-table", ""); 5 | $(".data-table").data("nested-table-columns", ""); 6 | window.location.reload(); 7 | <% elsif @table_settings.nested_table.present? %> 8 | $(".data-table").data("nested-table", "<%= @table_settings.nested_table %>"); 9 | $(".data-table").data("nested-table-columns", "<%= @nested_column_names %>"); 10 | window.location.reload(); 11 | <% end %> 12 | window['datatable'].draw(); 13 | <% else %> 14 | toastr.error('Unable to update table settings.'); 15 | <% end %> -------------------------------------------------------------------------------- /app/views/task_queues/_preview.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

Results

3 |
4 |
5 | 6 | 7 | <% if @task_queue_headers %> 8 | 9 | <% @task_queue_headers.each do |header|%> 10 | 11 | <% end %> 12 | 13 | <% end %> 14 | 15 | 16 | 17 |
<%= header.humanize %>
18 |
19 | -------------------------------------------------------------------------------- /app/views/task_queues/_preview_show.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <% task_queue_draggable_field_settings_container(@task_queue).each do |field| %> 9 |

<%= field[1]["title"] %>

10 |
11 | <% end %> 12 |
13 |
14 |
15 | 16 |
17 |
18 | <%= render 'shared/activity_history_template', feedable_type: 'task_queue', feedable_id: @task_queue.id %> 19 |
20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /app/views/task_queues/_task_queue_builder.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= @database.id %> 3 |
4 |
5 |
6 |
7 |
8 |
9 | 10 |
11 |
-------------------------------------------------------------------------------- /app/views/task_queues/index_old.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |

Query Builder Rules

7 | 8 |
9 | 10 | 11 |
12 |
13 |
14 | 15 | 21 | -------------------------------------------------------------------------------- /app/views/task_queues/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 | -------------------------------------------------------------------------------- /app/views/task_queues/new/_new_queue_modal_screen_1.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 25 |
26 | -------------------------------------------------------------------------------- /app/views/task_queues/shared/_task_queue_navigation.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 15 |
16 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 4 | load Gem.bin_path('bundler', 'bundle') 5 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../config/application', __dir__) 3 | require_relative "../config/boot" 4 | require "rails/commands" 5 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative "../config/boot" 3 | require "rake" 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /bin/rspec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'bundler/setup' 3 | load Gem.bin_path('rspec-core', 'rspec') 4 | -------------------------------------------------------------------------------- /bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'pathname' 4 | require 'fileutils' 5 | include FileUtils 6 | 7 | # path to your application root. 8 | APP_ROOT = Pathname.new File.expand_path('..', __dir__) 9 | 10 | def system!(*args) 11 | system(*args) || abort("\n== Command #{args} failed ==") 12 | end 13 | 14 | chdir APP_ROOT do 15 | # This script is a way to update your development environment automatically. 16 | # Add necessary update steps to this file. 17 | 18 | puts '== Installing dependencies ==' 19 | system! 'gem install bundler --conservative' 20 | system('bundle check') || system!('bundle install') 21 | 22 | puts "\n== Updating database ==" 23 | system! 'bin/rails db:migrate' 24 | 25 | puts "\n== Removing old logs and tempfiles ==" 26 | system! 'bin/rails log:clear tmp:clear' 27 | 28 | puts "\n== Restarting application server ==" 29 | system! 'bin/rails restart' 30 | end 31 | -------------------------------------------------------------------------------- /bin/yarn: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_ROOT = File.expand_path('..', __dir__) 3 | Dir.chdir(APP_ROOT) do 4 | exec "yarn", *ARGV 5 | rescue Errno::ENOENT 6 | $stderr.puts "Yarn executable was not detected in the system." 7 | $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" 8 | exit 1 9 | end 10 | -------------------------------------------------------------------------------- /clock.rb: -------------------------------------------------------------------------------- 1 | require 'clockwork' 2 | include Clockwork 3 | 4 | handler do |job| 5 | puts "Running #{job}" 6 | end 7 | 8 | # every(3600, 'bundle exec rake dummy_client_database:reset') 9 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is used by Rack-based servers to start the application. 4 | 5 | require ::File.expand_path('../config/environment', __FILE__) 6 | run Rails.application 7 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative "boot" 2 | 3 | require "rails/all" 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(*Rails.groups) 8 | 9 | module Kuwinda 10 | class Application < Rails::Application 11 | # Initialize configuration defaults for originally generated Rails version. 12 | config.load_defaults 5.1 13 | 14 | config.autoloader = :classic 15 | # Settings in config/environments/* take precedence over those specified here. 16 | # Application configuration can go into files in config/initializers 17 | # -- all .rb files in that directory are automatically loaded after loading 18 | # the framework and any gems in your application. 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | begin 2 | load File.expand_path("../bin/spring", __dir__) 3 | rescue LoadError => e 4 | raise unless e.path.end_with?("/bin/spring") 5 | end 6 | 7 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 8 | 9 | require "bundler/setup" # Set up gems listed in the Gemfile. 10 | -------------------------------------------------------------------------------- /config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: test 6 | 7 | production: 8 | adapter: redis 9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> 10 | channel_prefix: kuwinda_production 11 | -------------------------------------------------------------------------------- /config/client_database.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | adapter: postgresql 3 | encoding: unicode 4 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 5 | host: <%= ENV['CLIENT_DATABASE_HOST'] %> 6 | username: <%= ENV['CLIENT_DATABASE_USER'] %> 7 | password: <%= ENV['CLIENT_DATABASE_PASSWORD'] %> 8 | reaping_frequency: 0 9 | 10 | development: 11 | <<: *default 12 | database: <%= ENV['CLIENT_DATABASE_URL'] %> 13 | 14 | test: 15 | <<: *default 16 | database: <%= ENV['CLIENT_DATABASE_DEVELOPMENT'] %> 17 | 18 | staging: 19 | <<: *default 20 | database: <%= ENV['CLIENT_DATABASE_URL'] %> 21 | 22 | production: 23 | <<: *default 24 | database: <%= ENV['CLIENT_DATABASE_URL'] %> 25 | -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | adapter: postgresql 3 | encoding: unicode 4 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 5 | host: <%= ENV['KUWINDA_DATABASE_HOST'] %> 6 | username: <%= ENV['KUWINDA_DATABASE_USER'] %> 7 | password: <%= ENV['KUWINDA_DATABASE_PASSWORD'] %> 8 | port: <%= ENV['KUWINDA_DATABASE_PORT'] { 5432 } %> 9 | reaping_frequency: 0 10 | 11 | development: 12 | <<: *default 13 | database: kuwinda_development 14 | 15 | test: 16 | <<: *default 17 | database: kuwinda_test 18 | 19 | staging: 20 | <<: *default 21 | database: kuwinda_staging 22 | 23 | production: 24 | <<: *default 25 | database: kuwinda_production 26 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative "application" 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ActiveSupport::Reloader.to_prepare do 4 | # ApplicationController.renderer.defaults.merge!( 5 | # http_host: 'example.org', 6 | # https: false 7 | # ) 8 | # end 9 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path. 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | # Add Yarn node_modules folder to the asset load path. 9 | Rails.application.config.assets.paths << Rails.root.join('node_modules') 10 | 11 | # Precompile additional assets. 12 | # application.js, application.css, and all non-JS/CSS in the app/assets 13 | # folder are already added. 14 | # Rails.application.config.assets.precompile += %w( admin.js admin.css ) 15 | 16 | Rails.application.config.assets.precompile += %w[ 17 | dataTable/datatables.min.js 18 | dragula/dragula.min.js 19 | shopify/draggable.bundle.js 20 | shopify/sortable.js 21 | sweetAlert/sweetalert.min.js 22 | moment/moment.min.js 23 | query-builder/query-builder.min.js 24 | ] 25 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code 7 | # by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'". 8 | Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"] 9 | -------------------------------------------------------------------------------- /config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /config/initializers/feature_policy.rb: -------------------------------------------------------------------------------- 1 | # Define an application-wide HTTP feature policy. For further 2 | # information see https://developers.google.com/web/updates/2018/06/feature-policy 3 | # 4 | # Rails.application.config.feature_policy do |f| 5 | # f.camera :none 6 | # f.gyroscope :none 7 | # f.microphone :none 8 | # f.usb :none 9 | # f.fullscreen :self 10 | # f.payment :self, "https://secure.example.com" 11 | # end 12 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [ 5 | :password, :secret, :token, :_key, :auth, :crypt, :salt, :certificate, :otp, :access, :private, :protected, :ssn 6 | ] 7 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /config/initializers/models.rb: -------------------------------------------------------------------------------- 1 | if Rails.env == "development" 2 | require_dependency "task_queue" 3 | # Dir.foreach("#{Rails.root}/app/models") do |model_name| 4 | # require_dependency model_name 5 | # end 6 | end -------------------------------------------------------------------------------- /config/initializers/new_framework_defaults_5_1.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | # 5 | # This file contains migration options to ease your Rails 5.1 upgrade. 6 | # 7 | # Once upgraded flip defaults one by one to migrate to the new default. 8 | # 9 | # Read the Guide for Upgrading Ruby on Rails for more info on each option. 10 | 11 | # Make `form_with` generate non-remote forms. 12 | Rails.application.config.action_view.form_with_generates_remote_forms = false 13 | 14 | # Unknown asset fallback will return the path passed in when the given 15 | # asset is not present in the asset pipeline. 16 | # Rails.application.config.assets.unknown_asset_fallback = false 17 | -------------------------------------------------------------------------------- /config/initializers/rolify.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Rolify.configure do |config| 4 | # By default ORM adapter is ActiveRecord. uncomment to use mongoid 5 | # config.use_mongoid 6 | 7 | # Dynamic shortcuts for User class (user.is_admin? like methods). Default is: false 8 | # config.use_dynamic_shortcuts 9 | 10 | # Configuration to remove roles from database once the last resource is removed. Default is: true 11 | # config.remove_role_if_empty = false 12 | end 13 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | Rails.application.config.session_store :cookie_store, key: '_kuwinda_session' 6 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /config/spring.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # %w[ 4 | # .ruby-version 5 | # .rbenv-vars 6 | # tmp/restart.txt 7 | # tmp/caching-dev.txt 8 | # ].each { |path| Spring.watch(path) } 9 | Spring.watch( 10 | ".ruby-version", 11 | ".rbenv-vars", 12 | "tmp/restart.txt", 13 | "tmp/caching-dev.txt" 14 | ) -------------------------------------------------------------------------------- /db/migrate/20180703105143_rename_users_table.rb: -------------------------------------------------------------------------------- 1 | class RenameUsersTable < ActiveRecord::Migration[5.1] 2 | def change 3 | rename_table :users, :admin_users 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20181012143652_create_activities.rb: -------------------------------------------------------------------------------- 1 | class CreateActivities < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :activities do |t| 4 | t.integer :user_id, null: false 5 | t.string :kind, null: false 6 | t.text :content 7 | t.timestamps null: false 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20181018150144_remove_user_id_from_activities.rb: -------------------------------------------------------------------------------- 1 | class RemoveUserIdFromActivities < ActiveRecord::Migration[5.1] 2 | def change 3 | remove_column :activities, :user_id 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20181018154253_add_polymorphic_assiociation_to_activities.rb: -------------------------------------------------------------------------------- 1 | class AddPolymorphicAssiociationToActivities < ActiveRecord::Migration[5.1] 2 | def self.up 3 | add_column :activities, :feedable_type, :string 4 | add_column :activities, :feedable_id, :integer 5 | add_index :activities, [:feedable_type, :feedable_id] 6 | change_column_null :activities, :feedable_type, false 7 | change_column_null :activities, :feedable_id, false 8 | end 9 | 10 | def self.down 11 | remove_column :activities, :feedable_type, :string 12 | remove_column :activities, :feedable_id, :integer 13 | remove_index :activities, [:feedable_type, :feedable_id] 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20181104112129_create_table_view_builder.rb: -------------------------------------------------------------------------------- 1 | class CreateTableViewBuilder < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :view_builders do |t| 4 | t.string :table_name, null: false 5 | t.jsonb :table_attributes, null: false, default: '{}' 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20181105125119_create_work_lists.rb: -------------------------------------------------------------------------------- 1 | class CreateWorkLists < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :work_lists do |t| 4 | t.string :name, null: false 5 | t.text :details 6 | t.jsonb :sql_query, null: false, default: [] 7 | t.timestamps null: false 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20181108114556_add_sql_filters_to_work_lists.rb: -------------------------------------------------------------------------------- 1 | class AddSqlFiltersToWorkLists < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :work_lists, :sql_filters, :jsonb, default: [] 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20181108143841_change_work_lists_sql_query_to_string.rb: -------------------------------------------------------------------------------- 1 | class ChangeWorkListsSqlQueryToString < ActiveRecord::Migration[5.1] 2 | def change 3 | remove_column :work_lists, :sql_query 4 | add_column :work_lists, :sql_query, :string 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20181108144047_add_outcomes_to_work_lists.rb: -------------------------------------------------------------------------------- 1 | class AddOutcomesToWorkLists < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :work_lists, :outcomes, :jsonb, default: [] 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20181116183747_add_data_table_name_to_work_lists.rb: -------------------------------------------------------------------------------- 1 | class AddDataTableNameToWorkLists < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :work_lists, :data_table_name, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20181122170852_add_visible_columns_to_work_list.rb: -------------------------------------------------------------------------------- 1 | class AddVisibleColumnsToWorkList < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :work_lists, :visible_columns, :jsonb, default: [] 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20181123181141_add_view_name_to_view_builder.rb: -------------------------------------------------------------------------------- 1 | class AddViewNameToViewBuilder < ActiveRecord::Migration[5.1] 2 | def self.up 3 | add_column :view_builders, :view_name, :string, required: true 4 | add_column :view_builders, :status, :string, required: true, default: 'pending' 5 | end 6 | 7 | def self.down 8 | remove_column :view_builders, :view_name 9 | remove_column :view_builders, :status 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20181217165628_add_name_and_company_to_admin_users.rb: -------------------------------------------------------------------------------- 1 | class AddNameAndCompanyToAdminUsers < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :admin_users, :first_name, :string 4 | add_column :admin_users, :last_name, :string 5 | add_column :admin_users, :company_name, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20181224073927_create_layout_settings_table.rb: -------------------------------------------------------------------------------- 1 | class CreateLayoutSettingsTable < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :layout_settings do |t| 4 | t.integer :layout_id, null: false 5 | t.string :primary_table 6 | t.boolean :show_status, default: false, null: false 7 | t.boolean :commentable, default: false, null: false 8 | t.string :parent_comments_table 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20181224123606_add_visible_columns_to_layout_settings.rb: -------------------------------------------------------------------------------- 1 | class AddVisibleColumnsToLayoutSettings < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :layout_settings, :visible_columns, :jsonb, default: [] 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190107134016_add_show_status_to_view_builders.rb: -------------------------------------------------------------------------------- 1 | class AddShowStatusToViewBuilders < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :view_builders, :show_status, :boolean, default: false, null: false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190107134621_add_commentable_to_view_builders.rb: -------------------------------------------------------------------------------- 1 | class AddCommentableToViewBuilders < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :view_builders, :commentable, :boolean, default: false, null: false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190107134849_add_parent_comment_table_to_view_builders.rb: -------------------------------------------------------------------------------- 1 | class AddParentCommentTableToViewBuilders < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :view_builders, :parent_comment_table, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190107135321_add_draggable_sections_to_view_builders.rb: -------------------------------------------------------------------------------- 1 | class AddDraggableSectionsToViewBuilders < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :view_builders, :draggable_fields_header_container, :jsonb, default: [] 4 | add_column :view_builders, :draggable_fields_side_container, :jsonb, default: [] 5 | add_column :view_builders, :draggable_fields_main_container, :jsonb, default: [] 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20190115204330_rename_draggable_containers_on_view_builders.rb: -------------------------------------------------------------------------------- 1 | class RenameDraggableContainersOnViewBuilders < ActiveRecord::Migration[5.1] 2 | def change 3 | remove_column :view_builders, :draggable_fields_header_container 4 | remove_column :view_builders, :draggable_fields_main_container 5 | add_column :view_builders, :draggable_fields_header_container1, :jsonb, default: [] 6 | add_column :view_builders, :draggable_fields_header_container2, :jsonb, default: [] 7 | add_column :view_builders, :draggable_fields_main_container1, :jsonb, default: [] 8 | add_column :view_builders, :draggable_fields_main_container2, :jsonb, default: [] 9 | add_column :view_builders, :draggable_fields_main_container3, :jsonb, default: [] 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20190303142750_add_hidden_columns_to_view_builder.rb: -------------------------------------------------------------------------------- 1 | class AddHiddenColumnsToViewBuilder < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :view_builders, :hidden_columns, :jsonb, default: [] 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190303142916_drop_layout_settings.rb: -------------------------------------------------------------------------------- 1 | class DropLayoutSettings < ActiveRecord::Migration[5.1] 2 | def change 3 | drop_table :layout_settings 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190402151253_add_callable_fields_to_layout_builder.rb: -------------------------------------------------------------------------------- 1 | class AddCallableFieldsToLayoutBuilder < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :view_builders, :callable_fields, :jsonb, default: [] 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190424163632_create_task_queues.rb: -------------------------------------------------------------------------------- 1 | class CreateTaskQueues < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :task_queues do |t| 4 | t.string :name, null: false 5 | t.text :details 6 | t.string :table 7 | t.timestamps null: false 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20190425152656_add_query_builder_rules_to_task_queues.rb: -------------------------------------------------------------------------------- 1 | class AddQueryBuilderRulesToTaskQueues < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :task_queues, :query_builder_rules, :jsonb, default: [] 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190429161124_add_raw_sql_to_task_queues.rb: -------------------------------------------------------------------------------- 1 | class AddRawSqlToTaskQueues < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :task_queues, :raw_sql, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190513161432_add_query_builder_sql_to_task_queues.rb: -------------------------------------------------------------------------------- 1 | class AddQueryBuilderSqlToTaskQueues < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :task_queues, :query_builder_sql, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190516152746_add_draggable_fields_to_task_queues.rb: -------------------------------------------------------------------------------- 1 | class AddDraggableFieldsToTaskQueues < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :task_queues, :draggable_fields, :jsonb, default: [] 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190518152319_add_license_key_to_admin_users.rb: -------------------------------------------------------------------------------- 1 | class AddLicenseKeyToAdminUsers < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :admin_users, :license_key, :string 4 | add_column :admin_users, :activation_id, :string 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20190528153818_add_outcome_settings_to_task_queues.rb: -------------------------------------------------------------------------------- 1 | class AddOutcomeSettingsToTaskQueues < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :task_queues, :success_outcome_title, :string 4 | add_column :task_queues, :success_outcome_timeout, :string 5 | add_column :task_queues, :failure_outcome_title, :string 6 | add_column :task_queues, :failure_outcome_timeout, :string 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20190531093327_add_full_license_to_admin_users.rb: -------------------------------------------------------------------------------- 1 | class AddFullLicenseToAdminUsers < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :admin_users, :full_license, :boolean, default: false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190605161402_create_task_queue_outcomes.rb: -------------------------------------------------------------------------------- 1 | class CreateTaskQueueOutcomes < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :task_queue_outcomes do |t| 4 | t.integer :task_queue_id, null: false 5 | t.string :task_queue_item_table, null: false 6 | t.string :task_queue_item_primary_key, null: false 7 | t.datetime :task_queue_item_reappear_at, null: false 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20190605161954_add_outcome_to_task_queue_outcomes.rb: -------------------------------------------------------------------------------- 1 | class AddOutcomeToTaskQueueOutcomes < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :task_queue_outcomes, :outcome, :string, null: false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190605164115_add_unique_constraint_to_task_queue_outcomes.rb: -------------------------------------------------------------------------------- 1 | class AddUniqueConstraintToTaskQueueOutcomes < ActiveRecord::Migration[5.1] 2 | def change 3 | add_index :task_queue_outcomes, [:task_queue_id, :task_queue_item_primary_key], unique: true, name: 'task_queue_item_unique' 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190620170803_add_related_tables_to_view_builder.rb: -------------------------------------------------------------------------------- 1 | class AddRelatedTablesToViewBuilder < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :view_builders, :related_tables, :jsonb, default: [] 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190627172016_create_data_table_states.rb: -------------------------------------------------------------------------------- 1 | class CreateDataTableStates < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :data_table_states do |t| 4 | t.string :table, null: false 5 | t.jsonb :state 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20190807161323_add_ignore_layout_modal_to_admin_user.rb: -------------------------------------------------------------------------------- 1 | class AddIgnoreLayoutModalToAdminUser < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :admin_users, :ignore_layout_modal, :boolean, default: false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190817190347_create_permissions.rb: -------------------------------------------------------------------------------- 1 | class CreatePermissions < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :permissions do |t| 4 | t.integer :admin_user_id 5 | t.string :name 6 | t.string :subject_class 7 | t.integer :subject_id 8 | t.string :action 9 | t.text :description 10 | 11 | t.timestamps 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20190901110701_rolify_create_roles.rb: -------------------------------------------------------------------------------- 1 | class RolifyCreateRoles < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table(:roles) do |t| 4 | t.string :name 5 | t.references :resource, :polymorphic => true 6 | 7 | t.timestamps 8 | end 9 | 10 | create_table(:admin_users_roles, :id => false) do |t| 11 | t.references :admin_user 12 | t.references :role 13 | end 14 | 15 | add_index(:roles, [ :name, :resource_type, :resource_id ]) 16 | add_index(:admin_users_roles, [ :admin_user_id, :role_id ]) 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /db/migrate/20190901125126_create_organisation_settings.rb: -------------------------------------------------------------------------------- 1 | class CreateOrganisationSettings < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :organisation_settings do |t| 4 | t.string :license_key 5 | t.string :activation_id 6 | t.boolean :full_license, default: false 7 | t.string :company_name 8 | end 9 | 10 | remove_column :admin_users, :company_name, :string 11 | remove_column :admin_users, :license_key, :string 12 | remove_column :admin_users, :activation_id, :string 13 | remove_column :admin_users, :full_license, :boolean, default: false 14 | 15 | remove_column :permissions, :admin_user_id, :integer 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /db/migrate/20191020103654_create_roles_permissions_table.rb: -------------------------------------------------------------------------------- 1 | class CreateRolesPermissionsTable < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :roles_permissions do |t| 4 | t.references :role 5 | t.references :permission 6 | end 7 | 8 | add_index(:roles_permissions, [ :role_id, :permission_id ]) 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20191107072022_add_status_to_admin_users.rb: -------------------------------------------------------------------------------- 1 | class AddStatusToAdminUsers < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :admin_users, :active, :boolean 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20191111185000_add_fields_to_roles.rb: -------------------------------------------------------------------------------- 1 | class AddFieldsToRoles < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :roles, :administrator, :boolean 4 | add_column :roles, :editor, :boolean 5 | add_column :roles, :export, :boolean 6 | add_column :roles, :export_limit, :integer 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20191123165832_create_target_table_settings.rb: -------------------------------------------------------------------------------- 1 | class CreateTargetTableSettings < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :target_table_settings do |t| 4 | t.string :name, null: false 5 | t.string :nested_table 6 | t.string :create_destination 7 | t.string :delete_destination 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20200111093456_add_database_table.rb: -------------------------------------------------------------------------------- 1 | class AddDatabaseTable < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :databases do |t| 4 | t.string :adapter, null: false 5 | t.string :encoding 6 | t.integer :pool, default: 5 7 | t.string :host, null: false 8 | t.string :username, null: false 9 | t.string :password_digest, null: false 10 | t.integer :port, null: false 11 | t.string :name 12 | t.string :friendly_name 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20200126125119_add_database_id_to_target_table_settings.rb: -------------------------------------------------------------------------------- 1 | class AddDatabaseIdToTargetTableSettings < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :target_table_settings, :database_id, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20200131135708_rename_database_password_field.rb: -------------------------------------------------------------------------------- 1 | class RenameDatabasePasswordField < ActiveRecord::Migration[5.1] 2 | def change 3 | rename_column :databases, :password_digest, :password 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20200325153714_add_editable_fields_to_target_table_settings.rb: -------------------------------------------------------------------------------- 1 | class AddEditableFieldsToTargetTableSettings < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :target_table_settings, :editable_fields, :jsonb 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20200408133632_add_relay_gem_to_databases.rb: -------------------------------------------------------------------------------- 1 | class AddRelayGemToDatabases < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :databases, :domain_url, :string 4 | add_column :databases, :gem_token, :string 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20200417114658_add_database_id_to_view_builders.rb: -------------------------------------------------------------------------------- 1 | class AddDatabaseIdToViewBuilders < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :view_builders, :database_id, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20200429134402_add_user_id_to_activity.rb: -------------------------------------------------------------------------------- 1 | class AddUserIdToActivity < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :activities, :user_id, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20200507093234_add_database_id_to_task_queues.rb: -------------------------------------------------------------------------------- 1 | class AddDatabaseIdToTaskQueues < ActiveRecord::Migration[5.2] 2 | def change 3 | add_column :task_queues, :database_id, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20200526152632_add_database_update_to_task_queues.rb: -------------------------------------------------------------------------------- 1 | class AddDatabaseUpdateToTaskQueues < ActiveRecord::Migration[5.2] 2 | def change 3 | add_column :task_queues, :success_database_update, :jsonb 4 | add_column :task_queues, :failure_database_update, :jsonb 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20200528143521_add_enabled_field_to_task_queue.rb: -------------------------------------------------------------------------------- 1 | class AddEnabledFieldToTaskQueue < ActiveRecord::Migration[5.2] 2 | def change 3 | add_column :task_queues, :enabled, :boolean, default: true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20200605105826_remove_null_restriction_task_queue_item.rb: -------------------------------------------------------------------------------- 1 | class RemoveNullRestrictionTaskQueueItem < ActiveRecord::Migration[5.2] 2 | def change 3 | change_column :task_queue_outcomes, :task_queue_item_reappear_at, :datetime, null: true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20200607113114_add_database_id_to_activities.rb: -------------------------------------------------------------------------------- 1 | class AddDatabaseIdToActivities < ActiveRecord::Migration[5.2] 2 | def change 3 | add_column :activities, :database_id, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20200628161056_add_service_name_to_active_storage_blobs.active_storage.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from active_storage (originally 20190112182829) 2 | class AddServiceNameToActiveStorageBlobs < ActiveRecord::Migration[6.0] 3 | def up 4 | unless column_exists?(:active_storage_blobs, :service_name) 5 | add_column :active_storage_blobs, :service_name, :string 6 | 7 | if configured_service = ActiveStorage::Blob.service.name 8 | ActiveStorage::Blob.unscoped.update_all(service_name: configured_service) 9 | end 10 | 11 | change_column :active_storage_blobs, :service_name, :string, null: false 12 | end 13 | end 14 | 15 | def down 16 | remove_column :active_storage_blobs, :service_name 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /db/migrate/20200628161057_create_active_storage_variant_records.active_storage.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from active_storage (originally 20191206030411) 2 | class CreateActiveStorageVariantRecords < ActiveRecord::Migration[6.0] 3 | def change 4 | unless table_exists?(:active_storage_variant_records) 5 | create_table :active_storage_variant_records do |t| 6 | t.belongs_to :blob, null: false, index: false 7 | t.string :variation_digest, null: false 8 | 9 | t.index %i[ blob_id variation_digest ], name: "index_active_storage_variant_records_uniqueness", unique: true 10 | t.foreign_key :active_storage_blobs, column: :blob_id 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20210117152849_remove_unique_constraint_task_queue_index.rb: -------------------------------------------------------------------------------- 1 | class RemoveUniqueConstraintTaskQueueIndex < ActiveRecord::Migration[6.1] 2 | def change 3 | remove_index :task_queue_outcomes, [:task_queue_id, :task_queue_item_primary_key] 4 | 5 | add_index :task_queue_outcomes, [:task_queue_id, :task_queue_item_primary_key], name: 'task_queue_item_index' 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20210130095843_add_primary_keys_to_target_table_settings.rb: -------------------------------------------------------------------------------- 1 | class AddPrimaryKeysToTargetTableSettings < ActiveRecord::Migration[6.1] 2 | def change 3 | add_column :target_table_settings, :primary_keys, :jsonb 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file should contain all the record creation needed to seed the database 4 | # with its default values. 5 | # The data can then be loaded with the rake db:seed (or created alongside the db 6 | # with db:setup). 7 | # 8 | # Examples: 9 | # 10 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 11 | # Mayor.create(name: 'Emanuel', city: cities.first) 12 | 13 | if Role.all.empty? 14 | Role.create([ 15 | { 16 | name: 'Admin', 17 | administrator: true, 18 | editor: true, 19 | export: true 20 | }, 21 | { 22 | name: 'Editor', 23 | administrator: false, 24 | editor: true, 25 | export: false 26 | }, 27 | { 28 | name: 'User', 29 | administrator: false, 30 | editor: false, 31 | export: false 32 | } 33 | ]) 34 | end 35 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | db: 5 | image: postgres:11.2-alpine 6 | ports: 7 | - '15432:5432' 8 | environment: 9 | POSTGRES_PASSWORD: postgres 10 | 11 | web: 12 | build: . 13 | command: bash 14 | volumes: 15 | - .:/app 16 | volumes_from: 17 | - bundle 18 | ports: 19 | - "3000:3000" 20 | env_file: 21 | - ./.env 22 | environment: 23 | BUNDLE_SILENCE_ROOT_WARNING: "true" 24 | HISTFILE: /app/.bash_history 25 | KUWINDA_DATABASE_HOST: db 26 | KUWINDA_DATABASE_USER: postgres 27 | KUWINDA_DATABASE_PASSWORD: postgres 28 | KUWINDA_DATABASE_PORT: 5432 29 | depends_on: 30 | - db 31 | 32 | bundle: 33 | image: busybox 34 | volumes: 35 | - /bundle 36 | -------------------------------------------------------------------------------- /log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/log/.keep -------------------------------------------------------------------------------- /public/assets/application-2de56da153daf022d256045cc5d53b7183a603e0af9863d1638f6087e9138d52.css.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/application-2de56da153daf022d256045cc5d53b7183a603e0af9863d1638f6087e9138d52.css.gz -------------------------------------------------------------------------------- /public/assets/application-60fcce1a154ba59fc56911eb77ae0500d846e0ab7b1bc414b9b6e497c632d2c1.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/application-60fcce1a154ba59fc56911eb77ae0500d846e0ab7b1bc414b9b6e497c632d2c1.js.gz -------------------------------------------------------------------------------- /public/assets/bootstrap/glyphicons-halflings-regular-13634da87d9e23f8c3ed9108ce1724d183a39ad072e73e1b3d8cbf646d2d0407.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/bootstrap/glyphicons-halflings-regular-13634da87d9e23f8c3ed9108ce1724d183a39ad072e73e1b3d8cbf646d2d0407.eot -------------------------------------------------------------------------------- /public/assets/bootstrap/glyphicons-halflings-regular-13634da87d9e23f8c3ed9108ce1724d183a39ad072e73e1b3d8cbf646d2d0407.eot.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/bootstrap/glyphicons-halflings-regular-13634da87d9e23f8c3ed9108ce1724d183a39ad072e73e1b3d8cbf646d2d0407.eot.gz -------------------------------------------------------------------------------- /public/assets/bootstrap/glyphicons-halflings-regular-42f60659d265c1a3c30f9fa42abcbb56bd4a53af4d83d316d6dd7a36903c43e5.svg.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/bootstrap/glyphicons-halflings-regular-42f60659d265c1a3c30f9fa42abcbb56bd4a53af4d83d316d6dd7a36903c43e5.svg.gz -------------------------------------------------------------------------------- /public/assets/bootstrap/glyphicons-halflings-regular-a26394f7ede100ca118eff2eda08596275a9839b959c226e15439557a5a80742.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/bootstrap/glyphicons-halflings-regular-a26394f7ede100ca118eff2eda08596275a9839b959c226e15439557a5a80742.woff -------------------------------------------------------------------------------- /public/assets/bootstrap/glyphicons-halflings-regular-e395044093757d82afcb138957d06a1ea9361bdcf0b442d06a18a8051af57456.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/bootstrap/glyphicons-halflings-regular-e395044093757d82afcb138957d06a1ea9361bdcf0b442d06a18a8051af57456.ttf -------------------------------------------------------------------------------- /public/assets/bootstrap/glyphicons-halflings-regular-e395044093757d82afcb138957d06a1ea9361bdcf0b442d06a18a8051af57456.ttf.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/bootstrap/glyphicons-halflings-regular-e395044093757d82afcb138957d06a1ea9361bdcf0b442d06a18a8051af57456.ttf.gz -------------------------------------------------------------------------------- /public/assets/bootstrap/glyphicons-halflings-regular-fe185d11a49676890d47bb783312a0cda5a44c4039214094e7957b4c040ef11c.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/bootstrap/glyphicons-halflings-regular-fe185d11a49676890d47bb783312a0cda5a44c4039214094e7957b4c040ef11c.woff2 -------------------------------------------------------------------------------- /public/assets/dataTable/datatables.min-39255d21ad998b32b2fc7eb4a073a5e0b89acb2fcbdd1f90d9a6fc3aa43f656b.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/dataTable/datatables.min-39255d21ad998b32b2fc7eb4a073a5e0b89acb2fcbdd1f90d9a6fc3aa43f656b.js.gz -------------------------------------------------------------------------------- /public/assets/dragula/dragula.min-94edc9ac879d6bd3fbfa48b57d9742a08cadbbafe2f3233a1a9116c03f2b070f.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/dragula/dragula.min-94edc9ac879d6bd3fbfa48b57d9742a08cadbbafe2f3233a1a9116c03f2b070f.js.gz -------------------------------------------------------------------------------- /public/assets/favicon-c14aaa6e1b7af86332a6497364938f801db6b1b3f4513dd70024bea60981a6ed.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/favicon-c14aaa6e1b7af86332a6497364938f801db6b1b3f4513dd70024bea60981a6ed.ico -------------------------------------------------------------------------------- /public/assets/favicon-c14aaa6e1b7af86332a6497364938f801db6b1b3f4513dd70024bea60981a6ed.ico.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/favicon-c14aaa6e1b7af86332a6497364938f801db6b1b3f4513dd70024bea60981a6ed.ico.gz -------------------------------------------------------------------------------- /public/assets/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2 -------------------------------------------------------------------------------- /public/assets/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot -------------------------------------------------------------------------------- /public/assets/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot.gz -------------------------------------------------------------------------------- /public/assets/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf -------------------------------------------------------------------------------- /public/assets/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf.gz -------------------------------------------------------------------------------- /public/assets/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg.gz -------------------------------------------------------------------------------- /public/assets/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff -------------------------------------------------------------------------------- /public/assets/images/Kuwinda_logo_full-blue-260.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/Kuwinda_logo_full-blue-260.png -------------------------------------------------------------------------------- /public/assets/images/icons/black-check-box-with-white-check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/black-check-box-with-white-check.png -------------------------------------------------------------------------------- /public/assets/images/icons/black-checkbox-empty.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/assets/images/icons/blue_cat_loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/blue_cat_loading.gif -------------------------------------------------------------------------------- /public/assets/images/icons/checked-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/checked-1.png -------------------------------------------------------------------------------- /public/assets/images/icons/circle-with-check-symbol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/circle-with-check-symbol.png -------------------------------------------------------------------------------- /public/assets/images/icons/circle-with-contrast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/circle-with-contrast.png -------------------------------------------------------------------------------- /public/assets/images/icons/circle-with-cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/circle-with-cross.png -------------------------------------------------------------------------------- /public/assets/images/icons/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/close.png -------------------------------------------------------------------------------- /public/assets/images/icons/column.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/column.png -------------------------------------------------------------------------------- /public/assets/images/icons/database-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/database-1.png -------------------------------------------------------------------------------- /public/assets/images/icons/database-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/database-2.png -------------------------------------------------------------------------------- /public/assets/images/icons/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/edit.png -------------------------------------------------------------------------------- /public/assets/images/icons/edit@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/edit@2x.png -------------------------------------------------------------------------------- /public/assets/images/icons/export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/export.png -------------------------------------------------------------------------------- /public/assets/images/icons/group-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/group-3.png -------------------------------------------------------------------------------- /public/assets/images/icons/import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/import.png -------------------------------------------------------------------------------- /public/assets/images/icons/magnifying-glass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/magnifying-glass.png -------------------------------------------------------------------------------- /public/assets/images/icons/minus-thick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/minus-thick.png -------------------------------------------------------------------------------- /public/assets/images/icons/plus-thick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/plus-thick.png -------------------------------------------------------------------------------- /public/assets/images/icons/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/plus.png -------------------------------------------------------------------------------- /public/assets/images/icons/report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/report.png -------------------------------------------------------------------------------- /public/assets/images/icons/settings-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/settings-1.png -------------------------------------------------------------------------------- /public/assets/images/icons/settings-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/settings-black.png -------------------------------------------------------------------------------- /public/assets/images/icons/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/settings.png -------------------------------------------------------------------------------- /public/assets/images/icons/team-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/images/icons/team-1.png -------------------------------------------------------------------------------- /public/assets/images/icons/triangle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/assets/logos/MissionKontrol-logo-inverted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/logos/MissionKontrol-logo-inverted.png -------------------------------------------------------------------------------- /public/assets/logos/MissionKontrol-logo-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/logos/MissionKontrol-logo-original.png -------------------------------------------------------------------------------- /public/assets/logos/kuwinda_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/logos/kuwinda_thumbnail.png -------------------------------------------------------------------------------- /public/assets/moment/moment.min-a4f754452a828ad057b1b61c20fcb99251bb8fa7db0dba8ca96417b8e5d59c6c.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/moment/moment.min-a4f754452a828ad057b1b61c20fcb99251bb8fa7db0dba8ca96417b8e5d59c6c.js.gz -------------------------------------------------------------------------------- /public/assets/patterns/header-profile-c05909898218a521d3bd19ba09a9a43338de6de5fdf1d3fc771b0ec28ae416c5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/patterns/header-profile-c05909898218a521d3bd19ba09a9a43338de6de5fdf1d3fc771b0ec28ae416c5.png -------------------------------------------------------------------------------- /public/assets/patterns/shattered-241155c2a3436bfc0a542fc31fe2908ff2bdfc90e1ac7e26c6ba715b01030dcf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/patterns/shattered-241155c2a3436bfc0a542fc31fe2908ff2bdfc90e1ac7e26c6ba715b01030dcf.png -------------------------------------------------------------------------------- /public/assets/query-builder/query-builder.min-252935bd0b5adbde13e1c5c616820f8a3a4f5cf645d690905bc728a80eeebe07.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/query-builder/query-builder.min-252935bd0b5adbde13e1c5c616820f8a3a4f5cf645d690905bc728a80eeebe07.js.gz -------------------------------------------------------------------------------- /public/assets/shopify/draggable.bundle-06c5ee80a53567c4a8f91f12174da87600991bb912404d73dbc1e66cbd8b2c94.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/shopify/draggable.bundle-06c5ee80a53567c4a8f91f12174da87600991bb912404d73dbc1e66cbd8b2c94.js.gz -------------------------------------------------------------------------------- /public/assets/shopify/sortable-8042a7900fcf2bf2e78d523d4cc0b896ec1151b893c9fe62dc702d6e047df669.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/shopify/sortable-8042a7900fcf2bf2e78d523d4cc0b896ec1151b893c9fe62dc702d6e047df669.js.gz -------------------------------------------------------------------------------- /public/assets/sweetAlert/sweetalert.min-c517df19a3eecca1c27936dfafd34163d0c1c81271aa6f914db8d5b1e7731d2f.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/assets/sweetAlert/sweetalert.min-c517df19a3eecca1c27936dfafd34163d0c1c81271aa6f914db8d5b1e7731d2f.js.gz -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /spec/factories/activity.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :activity do 5 | content { 'met with a user today' } 6 | kind { 'meeting' } 7 | 8 | trait :user do 9 | feedable_id { 1 } 10 | feedable_type { 'users' } 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/factories/admin_user.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :admin_user do 5 | email { FFaker::Internet.email } 6 | password { 'password' } 7 | password_confirmation { 'password' } 8 | active { true } 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/factories/database.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :database do 5 | friendly_name { 'Test Company' } 6 | adapter { 'postgresql' } 7 | host { ENV['DEMO_CLIENT_DB_HOST'] } 8 | port { 5432 } 9 | name { ENV['DEMO_CLIENT_DB_NAME'] } 10 | username { ENV['DEMO_CLIENT_DB_USER'] } 11 | password { ENV['DEMO_CLIENT_DB_PASSWORD'] } 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/factories/organisation_setting.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :organisation_setting do 5 | company_name { 'Test Company' } 6 | activation_id { '1559143878' } 7 | license_key { 'license_key' } 8 | full_license { false } 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/factories/permission.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :permission do 5 | subject_class { 'events' } 6 | action { 'view' } 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/factories/role.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :role do 5 | name { 'Admin' } 6 | administrator { false } 7 | editor { false } 8 | export { false } 9 | 10 | trait :admin do 11 | name { 'Admin' } 12 | administrator { true } 13 | editor { true } 14 | export { true } 15 | end 16 | 17 | trait :Editor do 18 | name { 'Editor' } 19 | end 20 | 21 | trait :editor do 22 | name { 'Editor' } 23 | editor { true } 24 | end 25 | 26 | trait :user do 27 | name { 'User' } 28 | end 29 | 30 | trait :export do 31 | export { true } 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /spec/factories/target_table_setting.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :target_table_setting do 5 | name { 'users' } 6 | nested_table { 'attending_events' } 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/factories/task_queue.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :task_queue do 5 | name { 'Task Queue Test' } 6 | table { FFaker::Name.name } 7 | database_id { 1 } 8 | details { 'Task Queue Details' } 9 | query_builder_rules { 'Query Builder Rules' } 10 | query_builder_sql { 'Query Builder SQL' } 11 | raw_sql { 'Raw SQL' } 12 | draggable_fields { [] } 13 | success_outcome_title { 'Customer has cookies' } 14 | success_outcome_timeout { 1 } 15 | failure_outcome_title { 'Customer does not have cookies' } 16 | failure_outcome_timeout { 30 } 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/factories/user.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :user do 5 | sequence(:email) { |i| "test#{i}@example.com" } 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/factories/view_builder.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :view_builder do 5 | view_name { 'View name' } 6 | table_name { FFaker::Name.name } 7 | status { 'active' } 8 | table_attributes do 9 | { 10 | 'visible_fields' => { 11 | '1' => 'area', 12 | '2' => 'level', 13 | '3' => 'plan', 14 | '4' => 'space' 15 | }, 16 | 'default_rows' => '10' 17 | } 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/factories/work_list.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :work_list do 5 | name { 'test' } 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/features/cache_connection_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | feature 'Loading table with corrrect permissions', js: true do 4 | background do 5 | sign_in_as_admin_with_license 6 | setup_tables_and_roles('events') 7 | create(:target_table_setting, name: @table, database_id: @database.id) 8 | give_role_all_permissions(@user.roles.first, 'events') 9 | end 10 | 11 | xscenario 'user with sales role with permissions to view table can view table page' do 12 | visit table_path(id: @database.id, table: 'events') 13 | expect(page).to have_content('Nairobi') 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/features/tables/add_record_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | feature 'Adding records with sufficient permissions', js: true do 4 | background do 5 | sign_in_admin_user_with_complete_table_settings('attending_events') 6 | end 7 | 8 | scenario 'with a single record selected creates the record' do 9 | find('.table--add-record-button').click 10 | fill_in 'record[transaction_id]', with: 5 11 | fill_in 'record[user_id]', with: 7 12 | click_button 'Save' 13 | expect(find("tr:last-child > td:nth-child(3)").text).to eq '5' 14 | end 15 | end 16 | 17 | feature 'Adding records without sufficient permissions', js: true do 18 | background do 19 | sign_in_admin_user_with_single_permissions('attending_events', :view) 20 | end 21 | 22 | scenario 'user cannot see the add option' do 23 | expect(page).not_to have_content('.table--add-record-button') 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/features/tables/admin_views_table_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | feature 'Admin views a table', type: :feature do 4 | before do 5 | delete_layout_for_users 6 | end 7 | 8 | xscenario 'clicking on a table will show the selected table' do 9 | VCR.use_cassette('license_key/validation_success') do 10 | sign_in_as_admin_with_license 11 | when_i_click_the_users_link 12 | end 13 | 14 | then_i_expect_to_be_redirected_to_the_users_table 15 | end 16 | end 17 | 18 | def delete_layout_for_users 19 | ViewBuilder.where(table_name: 'users').delete_all 20 | end 21 | 22 | def when_i_click_the_users_link 23 | within('#side-menu') do 24 | click_link 'users' 25 | end 26 | end 27 | 28 | def then_i_expect_to_be_redirected_to_the_users_table 29 | expect(page).to have_current_path(table_path(id: 'users', table: 'users')) 30 | end 31 | -------------------------------------------------------------------------------- /spec/features/tables/settings_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | feature 'Modifying Table settings', js: true do 4 | background do 5 | sign_in_admin_user_with_complete_table_settings('attending_events') 6 | end 7 | 8 | scenario 'editing editable and mandatory settings' do 9 | find('.table--settings').click 10 | select 'No', from: '[editable_fields][transaction_id][editable]' 11 | click_button 'Save' 12 | visit table_path(id: @database.id, table: 'attending_events') 13 | wait_for_ajax 14 | first('.data-table--select-input').click 15 | find('.filter-bar--edit > .white').click 16 | expect(page).not_to have_content("input[name$='[user_id]']") 17 | end 18 | end 19 | 20 | feature 'Modifying table settings without sufficient permissions', js: true do 21 | background do 22 | sign_in_admin_user_with_single_permissions('attending_events', :view) 23 | end 24 | 25 | scenario 'user cannot see the add option' do 26 | expect(page).not_to have_content('.table--settings') 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/features/users/admin_log_in_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | feature 'User login', js: true do 4 | scenario 'when user is active' do 5 | sign_in_as_user_with_license 6 | expect(page).to have_current_path(dashboard_path) 7 | end 8 | 9 | scenario 'when user is inactive' do 10 | create_org_with_license 11 | @user = create(:admin_user, active: false) 12 | sign_in_user 13 | expect(page).to have_current_path(new_admin_user_session_path) 14 | expect(page).to have_content 'Your account is not active. Please speak to an Administrator.' 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/fixtures/events.yml: -------------------------------------------------------------------------------- 1 | sailing: 2 | id: 1 3 | day: Tuesday 4 | user_id: 1 5 | 6 | snowboarding: 7 | id: 2 8 | day: Friday 9 | user_id: 3 10 | 11 | # ["id", "day", "area", "level", "plan", "space", "meeting", "created_at", "updated_at", "user_id"] 12 | -------------------------------------------------------------------------------- /spec/fixtures/users.yml: -------------------------------------------------------------------------------- 1 | marko: 2 | id: 1 3 | name: Marko 4 | email: marko@example.com 5 | 6 | # "id", 7 | # "email", 8 | # "encrypted_password", 9 | # "reset_password_token", 10 | # "reset_password_sent_at", 11 | # "remember_created_at", 12 | # "sign_in_count", 13 | # "current_sign_in_at", 14 | # "last_sign_in_at", 15 | # "current_sign_in_ip", 16 | # "last_sign_in_ip", 17 | # "created_at", 18 | # "updated_at", 19 | # "provider", 20 | # "uid", 21 | # "user", 22 | # "name", 23 | # "image_file_name", 24 | # "image_content_type", 25 | # "image_file_size", 26 | # "image_updated_at", 27 | # "level", 28 | # "choice", 29 | # "number" 30 | -------------------------------------------------------------------------------- /spec/support/features/target_database_helpers.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Features 4 | module TargetDatabaseHelpers 5 | def connect_to_target_database(database) 6 | @connection = establish_connection(database) 7 | @connection.connection 8 | end 9 | 10 | def remove_connection_to_target_database 11 | ActiveRecord::Base.remove_connection(@connection) 12 | end 13 | 14 | def establish_connection(database) 15 | ActiveRecord::Base.establish_connection( 16 | adapter: database.adapter, 17 | host: database.host, 18 | username: database.username, 19 | password: database.password, 20 | database: database.name, 21 | port: database.port 22 | ) 23 | end 24 | end 25 | end 26 | 27 | RSpec.configure do |config| 28 | config.include Features::TargetDatabaseHelpers, type: :feature 29 | end 30 | -------------------------------------------------------------------------------- /spec/support/time_helpers.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.configure do |config| 4 | config.include ActiveSupport::Testing::TimeHelpers 5 | end 6 | -------------------------------------------------------------------------------- /spec/support/unit/fake_active_record.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class FakeActiveRecord 4 | COLUMNS = %w[name].freeze 5 | 6 | def respond_to_missing?(method_name) 7 | COLUMNS.include?(method_name.to_s) || super 8 | end 9 | 10 | def method_missing(method_name, *args) 11 | if respond_to?(method_name) 12 | instance_variable_get("@#{method_name}") 13 | else 14 | super 15 | end 16 | end 17 | 18 | def self.define_attribute_methods 19 | COLUMNS.each do |name| 20 | define_method(name) { instance_variable_get("@#{name}") } 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/support/wait_for_ajax.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module WaitForAjax 4 | def wait_for_ajax 5 | Timeout.timeout(25) do 6 | loop until finished_all_ajax_requests? 7 | end 8 | end 9 | 10 | def finished_all_ajax_requests? 11 | page.evaluate_script('jQuery.active').zero? 12 | end 13 | end 14 | 15 | RSpec.configure do |config| 16 | config.include WaitForAjax, type: :feature 17 | end 18 | -------------------------------------------------------------------------------- /spec/unit/lib/kuwinda/presenter/list_available_tables_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe Kuwinda::Presenter::ListAvailableTables do 6 | subject { list_tables.call } 7 | 8 | let(:list_tables) do 9 | described_class.new(database_connection) 10 | end 11 | let(:database_connection) do 12 | Kuwinda::UseCase::DatabaseConnection.new(database).execute 13 | end 14 | let(:database) { create(:database) } 15 | 16 | context 'listing tables' do 17 | it 'displays the available tables' do 18 | expect(subject).to include('attending_events', 'users') 19 | end 20 | 21 | it 'does not display the schema_migrations table' do 22 | expect(subject).to_not include('schema_migrations') 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/unit/lib/kuwinda/presenter/list_table_fields_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe Kuwinda::Presenter::ListTableFields do 6 | subject { list_fields.call } 7 | 8 | let(:list_fields) do 9 | described_class.new(database_connection, table) 10 | end 11 | let(:database_connection) do 12 | Kuwinda::UseCase::DatabaseConnection.new(database).execute 13 | end 14 | let(:database) { create(:database) } 15 | let(:table) { 'Users' } 16 | 17 | context 'listing connections' do 18 | it 'displays the available table fields' do 19 | expect(subject).to include('email', 'name') 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/unit/lib/kuwinda/presenter/list_table_fields_with_type_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe Kuwinda::Presenter::ListTableFieldsWithType do 6 | subject { list_fields_with_type.call } 7 | 8 | let(:list_fields_with_type) do 9 | described_class.new(database_connection, table) 10 | end 11 | let(:database_connection) do 12 | Kuwinda::UseCase::DatabaseConnection.new(database).execute 13 | end 14 | let(:database) { create(:database) } 15 | let(:table) { 'Users' } 16 | 17 | context 'listing connections' do 18 | it 'displays the available tables their types' do 19 | expect(subject).to include(["id", "integer", "Users"], ["email", "string", "Users"]) 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/unit/lib/kuwinda/presenter/retrieve_data_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe Kuwinda::Presenter::RetrieveData do 4 | subject { retrieve_data.call } 5 | 6 | let(:retrieve_data) do 7 | described_class.new(database_connection, view_builder, query_limiter) 8 | end 9 | let(:database_connection) do 10 | Kuwinda::UseCase::DatabaseConnection.new(database).execute 11 | end 12 | let(:database) { create(:database) } 13 | let(:view_builder) { create(:view_builder) } 14 | let(:query_limiter) { 'WHERE user_id = 3' } 15 | let(:expected_result) do 16 | { 17 | 0 => ['London', 'pro', 'gold', 6], 18 | 1 => ['Morzine', 'beginner', 'silver', 2] 19 | } 20 | end 21 | 22 | # TODO: this is failing intermittently due to a different id 23 | # create on every run, expected_result is not always consistent 24 | context 'retrieving data' do 25 | xit 'returns the correct fields from the table' do 26 | expect(subject).to eq expected_result 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /spec/unit/lib/kuwinda/use_case/database_connection_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe Kuwinda::UseCase::DatabaseConnection do 6 | context 'when establishing a database connection' do 7 | subject { described_class.new(database).execute } 8 | 9 | let(:database) { create(:database) } 10 | let(:expected_result) do 11 | %w[attending_events schema_migrations welcomes users transactions companies] 12 | end 13 | # TODO: more specific testing of error messages - InvalidClientDatabaseError not valid 14 | 15 | it 'establishes an active connection' do 16 | expect(subject.connect.connection.active?).to eq true 17 | end 18 | 19 | it 'can list the tables available in the database' do 20 | expect(subject.connect.connection.tables).to match_array expected_result 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/unit/models/database_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe Database do 4 | let(:database) { build(:database, password: password) } 5 | 6 | describe '#encrypt_database_password' do 7 | subject { database.encrypt_database_password } 8 | let(:password) { 'password' } 9 | 10 | context 'when saving the database' do 11 | it 'encrypts the password' do 12 | database.save 13 | expect(database.password).not_to eq password 14 | end 15 | end 16 | 17 | context 'when password has been encrypted' do 18 | context 'and trying to save the database with the encypted password' do 19 | it 'saves the originally encrypted password' do 20 | database.save 21 | encrypted_password = database.password 22 | database.password = encrypted_password 23 | database.save 24 | expect(database.password).to eq encrypted_password 25 | end 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /spec/unit/models/sql_filter_factory_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe SQLFilterFactory do 6 | it 'responds to .build_sql_filter' do 7 | expect(described_class).to respond_to(:build_sql_filter) 8 | end 9 | 10 | describe '.build_sql_filter' do 11 | context 'when sql filter kind is equal' do 12 | it 'returns a SQLFilter::Equal filter' do 13 | filter_attributes = {} 14 | filter_attributes['kind'] = 'equal' 15 | actual = described_class.build_sql_filter(filter_attributes) 16 | expect(actual).to be_a(SQLFilter::Equal) 17 | end 18 | end 19 | 20 | context 'when sql filter kind is unknown' do 21 | it 'returns nil' do 22 | filter_attributes = {} 23 | filter_attributes['kind'] = 'notknown' 24 | actual = described_class.build_sql_filter(filter_attributes) 25 | expect(actual).to be_nil 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /spec/unit/models/task_queue_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe TaskQueue do 6 | let(:a_task_queue) { described_class.new } 7 | 8 | it 'responds to name' do 9 | expect(a_task_queue).to respond_to(:name) 10 | end 11 | 12 | it 'responds to details' do 13 | expect(a_task_queue).to respond_to(:details) 14 | end 15 | 16 | it 'responds to query_builder_rules' do 17 | expect(a_task_queue).to respond_to(:query_builder_rules) 18 | end 19 | 20 | it 'responds to query_builder_sql' do 21 | expect(a_task_queue).to respond_to(:query_builder_sql) 22 | end 23 | 24 | it 'responds to table' do 25 | expect(a_task_queue).to respond_to(:table) 26 | end 27 | 28 | it 'is invalid without a name' do 29 | a_task_queue.name = nil 30 | a_task_queue.valid? 31 | expect(a_task_queue.errors.keys).to include(:name) 32 | end 33 | 34 | it 'is invalid without a table' do 35 | a_task_queue.table = nil 36 | a_task_queue.valid? 37 | expect(a_task_queue.errors.keys).to include(:table) 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/unit/models/view_builder_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe ViewBuilder, type: :model do 6 | describe 'validations' do 7 | it 'requires a table_name' do 8 | view_builder = described_class.new 9 | view_builder.valid? 10 | expect(view_builder.errors[:table_name]).to include("can't be blank") 11 | end 12 | end 13 | 14 | describe 'configurations' do 15 | it 'can save which fields to use for the view' do 16 | view_builder = described_class.new(table_name: 'Users', table_attributes: { visible: 'email' }) 17 | expect(view_builder.table_attributes['visible']).to include('email') 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /vendor/assets/fonts/Casino_Hand/casino_hand-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/fonts/Casino_Hand/casino_hand-webfont.eot -------------------------------------------------------------------------------- /vendor/assets/fonts/Casino_Hand/casino_hand-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/fonts/Casino_Hand/casino_hand-webfont.ttf -------------------------------------------------------------------------------- /vendor/assets/fonts/Casino_Hand/casino_hand-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/fonts/Casino_Hand/casino_hand-webfont.woff -------------------------------------------------------------------------------- /vendor/assets/images/animated-overlay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/animated-overlay.gif -------------------------------------------------------------------------------- /vendor/assets/images/blueimp/img/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/blueimp/img/error.png -------------------------------------------------------------------------------- /vendor/assets/images/blueimp/img/error.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /vendor/assets/images/blueimp/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/blueimp/img/loading.gif -------------------------------------------------------------------------------- /vendor/assets/images/blueimp/img/play-pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/blueimp/img/play-pause.png -------------------------------------------------------------------------------- /vendor/assets/images/blueimp/img/play-pause.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /vendor/assets/images/blueimp/img/video-play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/blueimp/img/video-play.png -------------------------------------------------------------------------------- /vendor/assets/images/blueimp/img/video-play.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /vendor/assets/images/bootstrap-colorpicker/alpha-horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/bootstrap-colorpicker/alpha-horizontal.png -------------------------------------------------------------------------------- /vendor/assets/images/bootstrap-colorpicker/alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/bootstrap-colorpicker/alpha.png -------------------------------------------------------------------------------- /vendor/assets/images/bootstrap-colorpicker/hue-horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/bootstrap-colorpicker/hue-horizontal.png -------------------------------------------------------------------------------- /vendor/assets/images/bootstrap-colorpicker/hue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/bootstrap-colorpicker/hue.png -------------------------------------------------------------------------------- /vendor/assets/images/bootstrap-colorpicker/saturation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/bootstrap-colorpicker/saturation.png -------------------------------------------------------------------------------- /vendor/assets/images/chosen-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/chosen-sprite.png -------------------------------------------------------------------------------- /vendor/assets/images/chosen-sprite@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/chosen-sprite@2x.png -------------------------------------------------------------------------------- /vendor/assets/images/green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/green.png -------------------------------------------------------------------------------- /vendor/assets/images/green@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/green@2x.png -------------------------------------------------------------------------------- /vendor/assets/images/iCheck/green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/iCheck/green.png -------------------------------------------------------------------------------- /vendor/assets/images/iCheck/green@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/iCheck/green@2x.png -------------------------------------------------------------------------------- /vendor/assets/images/images/animated-overlay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/images/animated-overlay.gif -------------------------------------------------------------------------------- /vendor/assets/images/images/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/images/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /vendor/assets/images/images/ui-bg_flat_75_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/images/ui-bg_flat_75_ffffff_40x100.png -------------------------------------------------------------------------------- /vendor/assets/images/images/ui-bg_glass_55_fbf9ee_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/images/ui-bg_glass_55_fbf9ee_1x400.png -------------------------------------------------------------------------------- /vendor/assets/images/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /vendor/assets/images/images/ui-bg_glass_75_dadada_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/images/ui-bg_glass_75_dadada_1x400.png -------------------------------------------------------------------------------- /vendor/assets/images/images/ui-bg_glass_75_e6e6e6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/images/ui-bg_glass_75_e6e6e6_1x400.png -------------------------------------------------------------------------------- /vendor/assets/images/images/ui-bg_glass_95_fef1ec_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/images/ui-bg_glass_95_fef1ec_1x400.png -------------------------------------------------------------------------------- /vendor/assets/images/images/ui-bg_highlight-soft_75_cccccc_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/images/ui-bg_highlight-soft_75_cccccc_1x100.png -------------------------------------------------------------------------------- /vendor/assets/images/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /vendor/assets/images/images/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/images/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /vendor/assets/images/images/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/images/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /vendor/assets/images/images/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/images/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /vendor/assets/images/images/ui-icons_cd0a0a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/images/ui-icons_cd0a0a_256x240.png -------------------------------------------------------------------------------- /vendor/assets/images/sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/sort.png -------------------------------------------------------------------------------- /vendor/assets/images/sort_asc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/sort_asc.png -------------------------------------------------------------------------------- /vendor/assets/images/sort_desc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/sort_desc.png -------------------------------------------------------------------------------- /vendor/assets/images/sprite-skin-flat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/sprite-skin-flat.png -------------------------------------------------------------------------------- /vendor/assets/images/sprite-skin-flat2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/sprite-skin-flat2.png -------------------------------------------------------------------------------- /vendor/assets/images/sprite-skin-nice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/sprite-skin-nice.png -------------------------------------------------------------------------------- /vendor/assets/images/sprite-skin-simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/sprite-skin-simple.png -------------------------------------------------------------------------------- /vendor/assets/images/spritemap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/spritemap.png -------------------------------------------------------------------------------- /vendor/assets/images/spritemap@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/images/spritemap@2x.png -------------------------------------------------------------------------------- /vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/javascripts/.keep -------------------------------------------------------------------------------- /vendor/assets/stylesheets/dragula/dragula.min.css: -------------------------------------------------------------------------------- 1 | .gu-mirror{position:fixed!important;margin:0!important;z-index:9999!important;opacity:.8;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";filter:alpha(opacity=80)}.gu-hide{display:none!important}.gu-unselectable{-webkit-user-select:none!important;-moz-user-select:none!important;-ms-user-select:none!important;user-select:none!important}.gu-transit{opacity:.2;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";filter:alpha(opacity=20)} -------------------------------------------------------------------------------- /vendor/assets/stylesheets/images/bootstrap-colorpicker/alpha-horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/images/bootstrap-colorpicker/alpha-horizontal.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/images/bootstrap-colorpicker/alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/images/bootstrap-colorpicker/alpha.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/images/bootstrap-colorpicker/hue-horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/images/bootstrap-colorpicker/hue-horizontal.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/images/bootstrap-colorpicker/hue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/images/bootstrap-colorpicker/hue.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/images/bootstrap-colorpicker/saturation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/images/bootstrap-colorpicker/saturation.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/images/sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/images/sort.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/images/sort_asc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/images/sort_asc.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/images/sort_desc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/images/sort_desc.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/images/sprite-skin-flat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/images/sprite-skin-flat.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/images/sprite-skin-flat2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/images/sprite-skin-flat2.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/images/sprite-skin-nice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/images/sprite-skin-nice.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/images/sprite-skin-simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/images/sprite-skin-simple.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/images/spritemap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/images/spritemap.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/images/spritemap@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/images/spritemap@2x.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/jQueryUI/images/animated-overlay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/jQueryUI/images/animated-overlay.gif -------------------------------------------------------------------------------- /vendor/assets/stylesheets/jQueryUI/images/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/jQueryUI/images/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/jQueryUI/images/ui-bg_flat_75_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/jQueryUI/images/ui-bg_flat_75_ffffff_40x100.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/jQueryUI/images/ui-bg_glass_55_fbf9ee_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/jQueryUI/images/ui-bg_glass_55_fbf9ee_1x400.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/jQueryUI/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/jQueryUI/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/jQueryUI/images/ui-bg_glass_75_dadada_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/jQueryUI/images/ui-bg_glass_75_dadada_1x400.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/jQueryUI/images/ui-bg_glass_75_e6e6e6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/jQueryUI/images/ui-bg_glass_75_e6e6e6_1x400.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/jQueryUI/images/ui-bg_glass_95_fef1ec_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/jQueryUI/images/ui-bg_glass_95_fef1ec_1x400.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/jQueryUI/images/ui-bg_highlight-soft_75_cccccc_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/jQueryUI/images/ui-bg_highlight-soft_75_cccccc_1x100.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/jQueryUI/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/jQueryUI/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/jQueryUI/images/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/jQueryUI/images/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/jQueryUI/images/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/jQueryUI/images/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/jQueryUI/images/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/jQueryUI/images/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /vendor/assets/stylesheets/jQueryUI/images/ui-icons_cd0a0a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mission-Kontrol/MissionKontrol/3164f543272d1299663be147300217f9067682cb/vendor/assets/stylesheets/jQueryUI/images/ui-icons_cd0a0a_256x240.png --------------------------------------------------------------------------------