├── log
└── .keep
├── storage
└── .keep
├── tmp
└── .keep
├── vendor
└── .keep
├── lib
├── assets
│ └── .keep
└── tasks
│ ├── .keep
│ ├── company.rake
│ ├── format.rake
│ └── graphql.rake
├── public
├── favicon.ico
├── apple-touch-icon.png
├── apple-touch-icon-precomposed.png
├── images
│ └── avatar.jpg
└── robots.txt
├── .ruby-version
├── app
├── assets
│ ├── images
│ │ ├── .keep
│ │ └── dummy
│ │ │ ├── photos
│ │ │ ├── Alana.jpg
│ │ │ └── Cassie.jpg
│ │ │ └── logos
│ │ │ ├── drag.svg
│ │ │ └── drag-black.svg
│ └── config
│ │ └── manifest.js
├── graphql
│ ├── types
│ │ ├── .keep
│ │ ├── base_input_object.rb
│ │ ├── role_type.rb
│ │ ├── current_user_type.rb
│ │ ├── user_list_type.rb
│ │ ├── task_section_type.rb
│ │ ├── user_details_type.rb
│ │ ├── company_users_type.rb
│ │ ├── search_company_users_type.rb
│ │ ├── file_base_type.rb
│ │ ├── validation_error.rb
│ │ ├── form_error_type.rb
│ │ ├── search_companies_type.rb
│ │ ├── task_message_alert_type.rb
│ │ ├── team_type.rb
│ │ ├── subscription_type.rb
│ │ ├── user_for_password_reset_type.rb
│ │ ├── task_attributes.rb
│ │ ├── roles_user_type.rb
│ │ ├── task_message_type.rb
│ │ ├── user_type.rb
│ │ └── list_type.rb
│ ├── mutations
│ │ ├── .keep
│ │ ├── delete_task_message.rb
│ │ ├── delete_lists.rb
│ │ ├── delete_tasks.rb
│ │ ├── sign_out_user.rb
│ │ ├── update_task_message.rb
│ │ ├── send_reset_password_instructions.rb
│ │ ├── create_team.rb
│ │ ├── update_task.rb
│ │ ├── update_user_data.rb
│ │ ├── create_task.rb
│ │ └── remove_team_member.rb
│ └── prepdd_schema.rb
├── models
│ ├── concerns
│ │ └── .keep
│ ├── file_label.rb
│ ├── file_message.rb
│ ├── file_message_alert.rb
│ ├── task_section.rb
│ ├── user_notification_scope.rb
│ ├── file_base.rb
│ ├── subscription.rb
│ ├── user_notification_frequency.rb
│ ├── teams_user.rb
│ ├── file_task.rb
│ ├── users_company.rb
│ ├── file_version_task.rb
│ ├── task_message_alert.rb
│ ├── task_owner.rb
│ ├── lists_user.rb
│ ├── broker_company.rb
│ ├── file_version.rb
│ ├── parent_company.rb
│ ├── task_message.rb
│ ├── roles_user.rb
│ ├── team.rb
│ ├── role.rb
│ ├── list.rb
│ └── application_record.rb
├── controllers
│ ├── concerns
│ │ └── .keep
│ ├── welcome_controller.rb
│ ├── application_controller.rb
│ ├── api_controller.rb
│ ├── api
│ │ ├── tasks_controller.rb
│ │ ├── file_versions_controller.rb
│ │ ├── companies_controller.rb
│ │ └── users_controller.rb
│ └── graphql_controller.rb
├── views
│ ├── layouts
│ │ ├── mailer.text.erb
│ │ ├── mailer.html.erb
│ │ └── application.html.erb
│ ├── welcome
│ │ └── index.html.erb
│ └── devise
│ │ └── mailer
│ │ ├── password_change.html.erb
│ │ ├── confirmation_instructions.html.erb
│ │ ├── unlock_instructions.html.erb
│ │ ├── email_changed.html.erb
│ │ └── reset_password_instructions.html.erb
├── helpers
│ └── application_helper.rb
├── jobs
│ └── application_job.rb
├── javascript
│ ├── src
│ │ ├── modules
│ │ │ ├── layout
│ │ │ │ ├── index.tsx
│ │ │ │ └── components
│ │ │ │ │ ├── TopBar
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── components
│ │ │ │ │ │ └── StyledBadge.tsx
│ │ │ │ │ └── SideBar
│ │ │ │ │ └── index.tsx
│ │ │ ├── list
│ │ │ │ ├── ListPage
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── components
│ │ │ │ │ │ └── styled
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── StyledTabs.tsx
│ │ │ │ │ │ ├── StyledTableCell.tsx
│ │ │ │ │ │ ├── StyledTableRow.tsx
│ │ │ │ │ │ ├── StyledButton.tsx
│ │ │ │ │ │ └── StyledTab.tsx
│ │ │ │ └── CreateListPage
│ │ │ │ │ ├── components
│ │ │ │ │ ├── Header
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── CreateListStep
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── components
│ │ │ │ │ │ │ └── Alert.tsx
│ │ │ │ │ ├── CreateTemplateStep
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ └── SelectTemplateStep
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── components
│ │ │ │ │ │ ├── MAPane.tsx
│ │ │ │ │ │ ├── LegalPane.tsx
│ │ │ │ │ │ └── FinancePane.tsx
│ │ │ │ │ └── index.tsx
│ │ │ ├── task
│ │ │ │ ├── TaskPage
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── components
│ │ │ │ │ │ ├── Message
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── SidePanel
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── TaskTable
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── components
│ │ │ │ │ │ │ └── StyledBadge.tsx
│ │ │ │ │ │ └── TaskToolbar
│ │ │ │ │ │ └── index.tsx
│ │ │ │ └── CreateTaskPage
│ │ │ │ │ ├── components
│ │ │ │ │ ├── Body
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ └── Header
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── CreateTaskPage.tsx
│ │ │ ├── user
│ │ │ │ ├── index.tsx
│ │ │ │ ├── components
│ │ │ │ │ ├── ProfilePane
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ └── NotificationPane
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── components
│ │ │ │ │ │ └── Dropdown.tsx
│ │ │ │ │ │ └── NotificationPane.tsx
│ │ │ │ ├── __tests__
│ │ │ │ │ └── UserProfile.test.tsx
│ │ │ │ └── UserProfile.tsx
│ │ │ ├── file
│ │ │ │ └── FilesPage
│ │ │ │ │ ├── components
│ │ │ │ │ ├── Body
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── Body.tsx
│ │ │ │ │ └── Header
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── FilesPage.tsx
│ │ │ ├── team
│ │ │ │ ├── index.tsx
│ │ │ │ └── components
│ │ │ │ │ ├── Searchbar
│ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── DetailPane
│ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── TableHeader
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── TableHeader.tsx
│ │ │ │ │ ├── TableToolbar
│ │ │ │ │ └── index.tsx
│ │ │ │ │ └── styled
│ │ │ │ │ ├── StyledTableCell.tsx
│ │ │ │ │ └── StyledTableRow.tsx
│ │ │ ├── company
│ │ │ │ ├── index.tsx
│ │ │ │ └── components
│ │ │ │ │ ├── FormPanel
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── components
│ │ │ │ │ │ ├── StyledTableRow.tsx
│ │ │ │ │ │ └── StyledTableCell.tsx
│ │ │ │ │ └── UploadPanel
│ │ │ │ │ └── index.tsx
│ │ │ ├── dashboard
│ │ │ │ └── index.tsx
│ │ │ ├── common
│ │ │ │ ├── NotAvailable.tsx
│ │ │ │ ├── NotFoundPage.tsx
│ │ │ │ ├── LoadingFallback.tsx
│ │ │ │ ├── DefaultUserImage.tsx
│ │ │ │ └── ConfirmModal.tsx
│ │ │ └── route
│ │ │ │ ├── team.tsx
│ │ │ │ ├── user.tsx
│ │ │ │ ├── list.tsx
│ │ │ │ ├── task.tsx
│ │ │ │ ├── company.tsx
│ │ │ │ └── app.tsx
│ │ ├── __mocks__
│ │ │ └── emptyAsset.ts
│ │ ├── constants
│ │ │ ├── keys.ts
│ │ │ ├── third_party_types
│ │ │ │ └── react-linkedin-login-oauth2.ts
│ │ │ ├── theme.ts
│ │ │ └── types.ts
│ │ ├── setupEnzyme.ts
│ │ ├── graphql
│ │ │ ├── queries
│ │ │ │ ├── AllRoles.ts
│ │ │ │ ├── UserLists.ts
│ │ │ │ ├── AllTemplates.ts
│ │ │ │ ├── UserForPasswordReset.ts
│ │ │ │ ├── __generated__
│ │ │ │ │ ├── AllRoles.ts
│ │ │ │ │ ├── UserForPasswordReset.ts
│ │ │ │ │ ├── publicTaskMessages.ts
│ │ │ │ │ ├── UserLists.ts
│ │ │ │ │ ├── privateTaskMessages.ts
│ │ │ │ │ ├── AllTemplates.ts
│ │ │ │ │ └── UserDetails.ts
│ │ │ │ ├── PublicTaskMessages.ts
│ │ │ │ ├── PrivateTaskMessages.ts
│ │ │ │ ├── UserDetails.ts
│ │ │ │ ├── CompanySettings.ts
│ │ │ │ ├── CurrentUser.ts
│ │ │ │ ├── CompanyUsers.ts
│ │ │ │ └── UserTasks.ts
│ │ │ ├── mutations
│ │ │ │ ├── SignOutUser.ts
│ │ │ │ ├── DeleteTasks.ts
│ │ │ │ ├── CreateTask.ts
│ │ │ │ ├── CreateCompany.ts
│ │ │ │ ├── UpdateUserPassword.ts
│ │ │ │ ├── __generated__
│ │ │ │ │ ├── deleteTasks.ts
│ │ │ │ │ ├── SignOutUser.ts
│ │ │ │ │ ├── CreateTask.ts
│ │ │ │ │ ├── AddListOwner.ts
│ │ │ │ │ ├── UpdateUserPassword.ts
│ │ │ │ │ ├── UpdateUserData.ts
│ │ │ │ │ ├── CreateCompany.ts
│ │ │ │ │ ├── SendPasswordResetInstructions.ts
│ │ │ │ │ ├── CreatePublicTaskMessage.ts
│ │ │ │ │ ├── CreatePrivateTaskMessage.ts
│ │ │ │ │ ├── InviteNewCompanyToList.ts
│ │ │ │ │ ├── CreateList.ts
│ │ │ │ │ └── SignInUser.ts
│ │ │ │ ├── SendPasswordResetInstructions.ts
│ │ │ │ ├── AddListOwner.ts
│ │ │ │ ├── UpdateUserData.ts
│ │ │ │ ├── CreatePrivateTaskMessage.ts
│ │ │ │ ├── CreateList.ts
│ │ │ │ ├── CreatePublicTaskMessage.ts
│ │ │ │ ├── SignInUser.ts
│ │ │ │ ├── InviteNewCompanyToList.ts
│ │ │ │ ├── RemoveTeamMember.ts
│ │ │ │ ├── CreateAssociatedCompany.ts
│ │ │ │ ├── RemoveCompanyMember.ts
│ │ │ │ ├── UpdateTeamMember.ts
│ │ │ │ ├── AddTeamMember.ts
│ │ │ │ ├── UpdateTask.ts
│ │ │ │ ├── AddTaskOwners.ts
│ │ │ │ └── SignUpUser.ts
│ │ │ ├── __generated__
│ │ │ │ └── globalTypes.ts
│ │ │ └── graphqlHelpers.ts
│ │ ├── helpers
│ │ │ ├── queries.ts
│ │ │ ├── roleHelpers.ts
│ │ │ └── __generated__
│ │ │ │ └── SearchCompanyUsers.ts
│ │ └── application.tsx
│ └── packs
│ │ └── application_pack.tsx
├── channels
│ └── application_cable
│ │ ├── channel.rb
│ │ └── connection.rb
├── mailers
│ └── application_mailer.rb
├── workers
│ └── company
│ │ ├── company_s3_bucket_creation_worker.rb
│ │ ├── company_kms_creation_worker.rb
│ │ └── remove_un_used_companies_worker.rb
└── policies
│ └── application_policy.rb
├── .browserslistrc
├── .rspec
├── db
├── data_schema.rb
├── migrate
│ ├── 20190819034701_rename_role_title.rb
│ ├── 20190812095935_add_company_id_to_teams.rb
│ ├── 20190903193053_remove_task_section_field.rb
│ ├── 20190913200833_add_list_number_to_tasks.rb
│ ├── 20190915022826_add_company_id_to_task_messages.rb
│ ├── 20190708203246_create_roles.rb
│ ├── 20190903100322_add_section_field_in_task.rb
│ ├── 20190817122452_add_title_to_subcription.rb
│ ├── 20190904160018_add_section_id_in_task.rb
│ ├── 20190904191854_adteam_id_in_lists_user.rb
│ ├── 20190819141140_add_team_id_to_user_roles.rb
│ ├── 20190910220419_add_reviewer_type_task_owner.rb
│ ├── 20190702001204_add_fields_to_user.rb
│ ├── 20190821153008_add_last_company_id_to_user.rb
│ ├── 20190903193648_create_task_sections.rb
│ ├── 20190913165628_add_is_public_to_task.rb
│ ├── 20190911184105_add_rank_on_list.rb
│ ├── 20190916060852_create_file_version_tasks.rb
│ ├── 20190717200222_create_teams.rb
│ ├── 20190708203644_create_roles_users.rb
│ ├── 20190717200930_create_teams_users.rb
│ ├── 20190904104719_create_lists_users.rb
│ ├── 20190911145904_create_user_notification_scopes.rb
│ ├── 20190911051521_create_file_bases.rb
│ ├── 20190814110824_create_users_companies.rb
│ ├── 20190911052855_create_file_tasks.rb
│ ├── 20190911153424_create_user_notification_frequencies.rb
│ ├── 20190817111651_add_company_settings.rb
│ ├── 20190712213325_add_uuid_to_users_for_omani_auth.rb
│ ├── 20190824162739_create_parent_companies.rb
│ ├── 20190730211803_add_s3_bucket_location_to_company.rb
│ ├── 20190824161311_create_broker_companies.rb
│ ├── 20190909181608_create_task_owners.rb
│ ├── 20190911154027_create_task_messages.rb
│ ├── 20190710202528_add_user_association_with_company.rb
│ ├── 20190911052002_create_file_message_alerts.rb
│ ├── 20190911051917_create_file_labels.rb
│ ├── 20190911051944_create_file_messages.rb
│ ├── 20190911155050_create_task_message_alerts.rb
│ ├── 20190706032837_add_full_name_to_user.rb
│ ├── 20190731170005_add_sessions_table.rb
│ ├── 20190708151108_create_companies.rb
│ ├── 20190911052305_create_file_versions.rb
│ ├── 20190830185711_create_tasks.rb
│ ├── 20190830182008_create_lists.rb
│ ├── 20190726063616_create_subscriptions.rb
│ ├── 20190715093652_add_bio_and_notification_fields_to_user.rb
│ └── 20190822034212_create_active_storage_tables.active_storage.rb
└── data
│ └── 20190708204424_add_basic_roles.rb
├── spec
├── factories
│ ├── file_tasks.rb
│ ├── teams_users.rb
│ ├── subscriptions.rb
│ ├── task_messages.rb
│ ├── users_companies.rb
│ ├── task_message_alerts.rb
│ ├── user_notification_frequencies.rb
│ ├── companies.rb
│ ├── teams.rb
│ ├── file_bases.rb
│ ├── file_message_alerts.rb
│ ├── roles.rb
│ ├── users.rb
│ ├── file_messages.rb
│ ├── file_labels.rb
│ └── file_versions.rb
├── support
│ ├── factory_bot.rb
│ └── graphql_spec_helper.rb
├── models
│ ├── team_spec.rb
│ ├── file_base_spec.rb
│ ├── file_label_spec.rb
│ ├── file_task_spec.rb
│ ├── teams_user_spec.rb
│ ├── file_message_spec.rb
│ ├── file_version_spec.rb
│ ├── subscription_spec.rb
│ ├── task_message_spec.rb
│ ├── users_company_spec.rb
│ ├── file_message_alert_spec.rb
│ ├── task_message_alert_spec.rb
│ ├── user_notification_frequency_spec.rb
│ ├── user_spec.rb
│ └── company_spec.rb
├── workers
│ └── company
│ │ ├── company_kms_creation_worker_spec.rb
│ │ ├── remove_un_used_companies_worker_spec.rb
│ │ └── company_s3_bucket_creation_worker_spec.rb
├── controllers
│ └── welcome_controller_spec.rb
└── graphql
│ ├── types
│ ├── current_user_type_spec.rb
│ ├── form_error_type_spec.rb
│ └── team_type_spec.rb
│ └── mutations
│ ├── create_company_spec.rb
│ ├── sign_up_user_spec.rb
│ ├── update_user_data.rb
│ ├── update_company_spec.rb
│ └── create_team_spec.rb
├── Procfile
├── Procfile.dev
├── .prettierrc
├── bin
├── bundle
├── rake
├── rails
├── yarn
├── webpack
├── webpack-dev-server
├── spring
├── update
└── setup
├── config
├── spring.rb
├── initializers
│ ├── session_store.rb
│ ├── sidekiq.rb
│ ├── mime_types.rb
│ ├── aws.rb
│ ├── filter_parameter_logging.rb
│ ├── application_controller_renderer.rb
│ ├── cookies_serializer.rb
│ ├── backtrace_silencers.rb
│ ├── wrap_parameters.rb
│ ├── assets.rb
│ ├── inflections.rb
│ └── content_security_policy.rb
├── environment.rb
├── webpack
│ ├── test.js
│ ├── development.js
│ ├── production.js
│ ├── environment.js
│ └── loaders
│ │ └── typescript.js
├── boot.rb
├── cable.yml
├── storage.yml
├── credentials.yml.enc
├── database.yml
├── routes.rb
├── locales
│ └── en.yml
└── application.rb
├── config.ru
├── postcss.config.js
├── Rakefile
├── jest.config.js
├── tsconfig.json
├── app.json
└── .gitignore
/log/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/storage/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tmp/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vendor/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/assets/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | ruby-2.6.3
--------------------------------------------------------------------------------
/app/assets/images/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/graphql/types/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.browserslistrc:
--------------------------------------------------------------------------------
1 | defaults
2 |
--------------------------------------------------------------------------------
/app/graphql/mutations/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/models/concerns/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --require spec_helper
2 |
--------------------------------------------------------------------------------
/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/apple-touch-icon-precomposed.png:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.text.erb:
--------------------------------------------------------------------------------
1 | <%= yield %>
2 |
--------------------------------------------------------------------------------
/app/assets/config/manifest.js:
--------------------------------------------------------------------------------
1 | //= link_tree ../images
2 |
--------------------------------------------------------------------------------
/app/views/welcome/index.html.erb:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper; end
2 |
--------------------------------------------------------------------------------
/app/models/file_label.rb:
--------------------------------------------------------------------------------
1 | class FileLabel < ApplicationRecord; end
2 |
--------------------------------------------------------------------------------
/app/models/file_message.rb:
--------------------------------------------------------------------------------
1 | class FileMessage < ApplicationRecord; end
2 |
--------------------------------------------------------------------------------
/app/jobs/application_job.rb:
--------------------------------------------------------------------------------
1 | class ApplicationJob < ActiveJob::Base; end
2 |
--------------------------------------------------------------------------------
/app/models/file_message_alert.rb:
--------------------------------------------------------------------------------
1 | class FileMessageAlert < ApplicationRecord; end
2 |
--------------------------------------------------------------------------------
/db/data_schema.rb:
--------------------------------------------------------------------------------
1 | # encoding: UTF-8
2 | DataMigrate::Data.define(version: 20190708204424)
3 |
--------------------------------------------------------------------------------
/app/models/task_section.rb:
--------------------------------------------------------------------------------
1 | class TaskSection < ApplicationRecord
2 | has_many :tasks
3 | end
4 |
--------------------------------------------------------------------------------
/app/models/user_notification_scope.rb:
--------------------------------------------------------------------------------
1 | class UserNotificationScope < ApplicationRecord; end
2 |
--------------------------------------------------------------------------------
/app/models/file_base.rb:
--------------------------------------------------------------------------------
1 | class FileBase < ApplicationRecord
2 | has_one_attached :template
3 | end
4 |
--------------------------------------------------------------------------------
/app/models/subscription.rb:
--------------------------------------------------------------------------------
1 | class Subscription < ApplicationRecord
2 | has_many :companies
3 | end
4 |
--------------------------------------------------------------------------------
/app/models/user_notification_frequency.rb:
--------------------------------------------------------------------------------
1 | class UserNotificationFrequency < ApplicationRecord; end
2 |
--------------------------------------------------------------------------------
/public/images/avatar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/PrepDD/HEAD/public/images/avatar.jpg
--------------------------------------------------------------------------------
/spec/factories/file_tasks.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :file_task do
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/spec/factories/teams_users.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :teams_user do
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/spec/support/factory_bot.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure { |config| config.include FactoryBot::Syntax::Methods }
2 |
--------------------------------------------------------------------------------
/app/graphql/types/base_input_object.rb:
--------------------------------------------------------------------------------
1 | class Types::BaseInputObject < GraphQL::Schema::InputObject; end
2 |
--------------------------------------------------------------------------------
/spec/factories/subscriptions.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :subscription do
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/spec/factories/task_messages.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :task_message do
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/spec/factories/users_companies.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :users_company do
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/layout/index.tsx:
--------------------------------------------------------------------------------
1 | import Layout from './Layout';
2 |
3 | export default Layout;
4 |
--------------------------------------------------------------------------------
/app/controllers/welcome_controller.rb:
--------------------------------------------------------------------------------
1 | class WelcomeController < ApplicationController
2 | def index; end
3 | end
4 |
--------------------------------------------------------------------------------
/app/models/teams_user.rb:
--------------------------------------------------------------------------------
1 | class TeamsUser < ApplicationRecord
2 | belongs_to :team
3 | belongs_to :user
4 | end
5 |
--------------------------------------------------------------------------------
/spec/factories/task_message_alerts.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :task_message_alert do
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | release: bundle exec rake db:migrate
2 | web: bundle exec rails server
3 | worker: bundle exec sidekiq -t 25
4 |
--------------------------------------------------------------------------------
/app/javascript/src/__mocks__/emptyAsset.ts:
--------------------------------------------------------------------------------
1 | // File left blank
2 |
3 | export default 'assets-not-supported-in-jest';
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/list/ListPage/index.tsx:
--------------------------------------------------------------------------------
1 | import ListPage from './ListPage';
2 |
3 | export default ListPage;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/task/TaskPage/index.tsx:
--------------------------------------------------------------------------------
1 | import TaskPage from './TaskPage';
2 |
3 | export default TaskPage;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/user/index.tsx:
--------------------------------------------------------------------------------
1 | import UserProfile from './UserProfile';
2 |
3 | export default UserProfile;
4 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 |
--------------------------------------------------------------------------------
/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | include Pundit
3 | end
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/file/FilesPage/components/Body/index.tsx:
--------------------------------------------------------------------------------
1 | import Body from './Body';
2 |
3 | export default Body;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/file/FilesPage/index.tsx:
--------------------------------------------------------------------------------
1 | import FilesPage from './FilesPage';
2 |
3 | export default FilesPage;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/layout/components/TopBar/index.tsx:
--------------------------------------------------------------------------------
1 | import TopBar from './TopBar';
2 |
3 | export default TopBar;
4 |
--------------------------------------------------------------------------------
/app/models/file_task.rb:
--------------------------------------------------------------------------------
1 | class FileTask < ApplicationRecord
2 | belongs_to :task
3 | belongs_to :file_version
4 | end
5 |
--------------------------------------------------------------------------------
/app/models/users_company.rb:
--------------------------------------------------------------------------------
1 | class UsersCompany < ApplicationRecord
2 | belongs_to :user
3 | belongs_to :company
4 | end
5 |
--------------------------------------------------------------------------------
/Procfile.dev:
--------------------------------------------------------------------------------
1 | redis: redis-server /usr/local/etc/redis.conf
2 | web: bundle exec rails server
3 | webpack: bin/webpack-dev-server
4 |
--------------------------------------------------------------------------------
/app/assets/images/dummy/photos/Alana.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/PrepDD/HEAD/app/assets/images/dummy/photos/Alana.jpg
--------------------------------------------------------------------------------
/app/assets/images/dummy/photos/Cassie.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamsuiux/PrepDD/HEAD/app/assets/images/dummy/photos/Cassie.jpg
--------------------------------------------------------------------------------
/app/channels/application_cable/channel.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Channel < ActionCable::Channel::Base; end
3 | end
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/layout/components/SideBar/index.tsx:
--------------------------------------------------------------------------------
1 | import SideBar from './SideBar';
2 |
3 | export default SideBar;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/task/CreateTaskPage/components/Body/index.tsx:
--------------------------------------------------------------------------------
1 | import Body from './Body';
2 |
3 | export default Body;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/team/index.tsx:
--------------------------------------------------------------------------------
1 | import TeamManagement from './TeamManagement';
2 |
3 | export default TeamManagement;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/company/index.tsx:
--------------------------------------------------------------------------------
1 | import CompanySettings from './CompanySettings';
2 |
3 | export default CompanySettings;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/file/FilesPage/components/Header/index.tsx:
--------------------------------------------------------------------------------
1 | import Header from './Header';
2 |
3 | export default Header;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/team/components/Searchbar/index.tsx:
--------------------------------------------------------------------------------
1 | import Searchbar from './Searchbar';
2 |
3 | export default Searchbar;
4 |
--------------------------------------------------------------------------------
/spec/factories/user_notification_frequencies.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :user_notification_frequency do
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/app/channels/application_cable/connection.rb:
--------------------------------------------------------------------------------
1 | module ApplicationCable
2 | class Connection < ActionCable::Connection::Base; end
3 | end
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/company/components/FormPanel/index.tsx:
--------------------------------------------------------------------------------
1 | import FormPanel from './FormPanel';
2 |
3 | export default FormPanel;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/list/CreateListPage/components/Header/index.tsx:
--------------------------------------------------------------------------------
1 | import Header from './Header';
2 |
3 | export default Header;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/task/CreateTaskPage/components/Header/index.tsx:
--------------------------------------------------------------------------------
1 | import Header from './Header';
2 |
3 | export default Header;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/task/TaskPage/components/Message/index.tsx:
--------------------------------------------------------------------------------
1 | import Message from './Message';
2 |
3 | export default Message;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/team/components/DetailPane/index.tsx:
--------------------------------------------------------------------------------
1 | import DetailPane from './DetailPane';
2 |
3 | export default DetailPane;
4 |
--------------------------------------------------------------------------------
/app/models/file_version_task.rb:
--------------------------------------------------------------------------------
1 | class FileVersionTask < ApplicationRecord
2 | belongs_to :task
3 | belongs_to :file_version
4 | end
5 |
--------------------------------------------------------------------------------
/app/models/task_message_alert.rb:
--------------------------------------------------------------------------------
1 | class TaskMessageAlert < ApplicationRecord
2 | belongs_to :task_message
3 | belongs_to :user
4 | end
5 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "tabWidth": 2,
4 | "semi": true,
5 | "singleQuote": true,
6 | "bracketSpacing": false
7 | }
--------------------------------------------------------------------------------
/app/javascript/src/modules/list/CreateListPage/index.tsx:
--------------------------------------------------------------------------------
1 | import CreateListPage from './CreateListPage';
2 |
3 | export default CreateListPage;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/task/CreateTaskPage/index.tsx:
--------------------------------------------------------------------------------
1 | import CreateTaskPage from './CreateTaskPage';
2 |
3 | export default CreateTaskPage;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/task/TaskPage/components/SidePanel/index.tsx:
--------------------------------------------------------------------------------
1 | import SidePanel from './SidePanel';
2 |
3 | export default SidePanel;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/task/TaskPage/components/TaskTable/index.tsx:
--------------------------------------------------------------------------------
1 | import TaskTable from './TaskTable';
2 |
3 | export default TaskTable;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/team/components/TableHeader/index.tsx:
--------------------------------------------------------------------------------
1 | import TableHeader from './TableHeader';
2 |
3 | export default TableHeader;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/user/components/ProfilePane/index.tsx:
--------------------------------------------------------------------------------
1 | import ProfilePane from './ProfilePane';
2 |
3 | export default ProfilePane;
4 |
--------------------------------------------------------------------------------
/app/models/task_owner.rb:
--------------------------------------------------------------------------------
1 | class TaskOwner < ApplicationRecord
2 | belongs_to :task_ownerable, polymorphic: true
3 | belongs_to :task
4 | end
5 |
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/spec/factories/companies.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :company do
3 | sequence(:name) { Faker::Company.name }
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/company/components/UploadPanel/index.tsx:
--------------------------------------------------------------------------------
1 | import UploadPanel from './UploadPanel';
2 |
3 | export default UploadPanel;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/team/components/TableToolbar/index.tsx:
--------------------------------------------------------------------------------
1 | import TableToolbar from './TableToolbar';
2 |
3 | export default TableToolbar;
4 |
--------------------------------------------------------------------------------
/app/mailers/application_mailer.rb:
--------------------------------------------------------------------------------
1 | class ApplicationMailer < ActionMailer::Base
2 | default from: 'from@example.com'
3 | layout 'mailer'
4 | end
5 |
--------------------------------------------------------------------------------
/config/spring.rb:
--------------------------------------------------------------------------------
1 | %w[
2 | .ruby-version
3 | .rbenv-vars
4 | tmp/restart.txt
5 | tmp/caching-dev.txt
6 | ].each { |path| Spring.watch(path) }
7 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/task/TaskPage/components/TaskToolbar/index.tsx:
--------------------------------------------------------------------------------
1 | import TaskToolbar from './TaskToolbar';
2 |
3 | export default TaskToolbar;
4 |
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require_relative 'config/environment'
4 |
5 | run Rails.application
6 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/user/components/NotificationPane/index.tsx:
--------------------------------------------------------------------------------
1 | import NotificationPane from './NotificationPane';
2 |
3 | export default NotificationPane;
4 |
--------------------------------------------------------------------------------
/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | Rails.application.config.session_store :active_record_store,
2 | key: 'prepdd_session'
3 |
--------------------------------------------------------------------------------
/spec/factories/teams.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :team do
3 | sequence(:name) { Faker::Company.name }
4 | association :company
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/spec/models/team_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe Team, type: :model do
4 | pending "add some examples to (or delete) #{__FILE__}"
5 | end
6 |
--------------------------------------------------------------------------------
/app/javascript/src/constants/keys.ts:
--------------------------------------------------------------------------------
1 | export const KEYS = {
2 | ARROW_LEFT: 37,
3 | ARROW_UP: 38,
4 | ARROW_RIGHT: 39,
5 | ARROW_DOWN: 40,
6 | ENTER: 13,
7 | };
8 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/dashboard/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default function Dashboard() {
4 | return
Dashboard Page
;
5 | }
6 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/list/CreateListPage/components/CreateListStep/index.tsx:
--------------------------------------------------------------------------------
1 | import CreateListStep from './CreateListStep';
2 |
3 | export default CreateListStep;
4 |
--------------------------------------------------------------------------------
/app/models/lists_user.rb:
--------------------------------------------------------------------------------
1 | class ListsUser < ApplicationRecord
2 | belongs_to :list
3 | belongs_to :user, optional: true
4 | belongs_to :team, optional: true
5 | end
6 |
--------------------------------------------------------------------------------
/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require_relative 'application'
3 |
4 | # Initialize the Rails application.
5 | Rails.application.initialize!
6 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/spec/factories/file_bases.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :file_basis, class: 'FileBase' do
3 | is_active { false }
4 | is_template { false }
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/spec/models/file_base_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe FileBase, type: :model do
4 | pending "add some examples to (or delete) #{__FILE__}"
5 | end
6 |
--------------------------------------------------------------------------------
/spec/models/file_label_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe FileLabel, type: :model do
4 | pending "add some examples to (or delete) #{__FILE__}"
5 | end
6 |
--------------------------------------------------------------------------------
/spec/models/file_task_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe FileTask, type: :model do
4 | pending "add some examples to (or delete) #{__FILE__}"
5 | end
6 |
--------------------------------------------------------------------------------
/spec/models/teams_user_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe TeamsUser, type: :model do
4 | pending "add some examples to (or delete) #{__FILE__}"
5 | end
6 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/common/NotAvailable.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default function NotAvailable() {
4 | return Not Available Data
;
5 | }
6 |
--------------------------------------------------------------------------------
/app/javascript/src/setupEnzyme.ts:
--------------------------------------------------------------------------------
1 | import {configure} from 'enzyme';
2 | import EnzymeAdapter from 'enzyme-adapter-react-16';
3 |
4 | configure({adapter: new EnzymeAdapter()});
5 |
--------------------------------------------------------------------------------
/db/migrate/20190819034701_rename_role_title.rb:
--------------------------------------------------------------------------------
1 | class RenameRoleTitle < ActiveRecord::Migration[5.2]
2 | def change
3 | rename_column :roles, :title, :name
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/spec/models/file_message_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe FileMessage, type: :model do
4 | pending "add some examples to (or delete) #{__FILE__}"
5 | end
6 |
--------------------------------------------------------------------------------
/spec/models/file_version_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe FileVersion, type: :model do
4 | pending "add some examples to (or delete) #{__FILE__}"
5 | end
6 |
--------------------------------------------------------------------------------
/spec/models/subscription_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe Subscription, type: :model do
4 | pending "add some examples to (or delete) #{__FILE__}"
5 | end
6 |
--------------------------------------------------------------------------------
/spec/models/task_message_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe TaskMessage, type: :model do
4 | pending "add some examples to (or delete) #{__FILE__}"
5 | end
6 |
--------------------------------------------------------------------------------
/spec/models/users_company_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe UsersCompany, type: :model do
4 | pending "add some examples to (or delete) #{__FILE__}"
5 | end
6 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/list/CreateListPage/components/CreateTemplateStep/index.tsx:
--------------------------------------------------------------------------------
1 | import CreateTemplateStep from './CreateTemplateStep';
2 |
3 | export default CreateTemplateStep;
4 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/list/CreateListPage/components/SelectTemplateStep/index.tsx:
--------------------------------------------------------------------------------
1 | import SelectTemplateStep from './SelectTemplateStep';
2 |
3 | export default SelectTemplateStep;
4 |
--------------------------------------------------------------------------------
/app/models/broker_company.rb:
--------------------------------------------------------------------------------
1 | class BrokerCompany < ApplicationRecord
2 | belongs_to :child_broker, class_name: 'Company'
3 | belongs_to :parent_broker, class_name: 'Company'
4 | end
5 |
--------------------------------------------------------------------------------
/app/models/file_version.rb:
--------------------------------------------------------------------------------
1 | class FileVersion < ApplicationRecord
2 | has_many :file_version_tasks
3 | has_many :tasks, through: :file_version_tasks
4 | has_one_attached :file
5 | end
6 |
--------------------------------------------------------------------------------
/app/models/parent_company.rb:
--------------------------------------------------------------------------------
1 | class ParentCompany < ApplicationRecord
2 | belongs_to :child_company, class_name: 'Company'
3 | belongs_to :parent_company, class_name: 'Company'
4 | end
5 |
--------------------------------------------------------------------------------
/spec/models/file_message_alert_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe FileMessageAlert, type: :model do
4 | pending "add some examples to (or delete) #{__FILE__}"
5 | end
6 |
--------------------------------------------------------------------------------
/spec/models/task_message_alert_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe TaskMessageAlert, type: :model do
4 | pending "add some examples to (or delete) #{__FILE__}"
5 | end
6 |
--------------------------------------------------------------------------------
/app/graphql/prepdd_schema.rb:
--------------------------------------------------------------------------------
1 | class PrepddSchema < GraphQL::Schema
2 | mutation(Types::MutationType)
3 | query(Types::QueryType)
4 |
5 | max_depth 6
6 | # max_complexity 1000
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20190812095935_add_company_id_to_teams.rb:
--------------------------------------------------------------------------------
1 | class AddCompanyIdToTeams < ActiveRecord::Migration[5.2]
2 | change_table :teams do |t|
3 | t.belongs_to :company
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/spec/factories/file_message_alerts.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :file_message_alert do
3 | file_message_id { 1 }
4 | user_id { 1 }
5 | is_read { false }
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/app/javascript/src/constants/third_party_types/react-linkedin-login-oauth2.ts:
--------------------------------------------------------------------------------
1 | declare module 'react-linkedin-login-oauth2' {
2 | export var LinkedIn: any;
3 | export var LinkedInPopUp: any;
4 | }
5 |
--------------------------------------------------------------------------------
/config/initializers/sidekiq.rb:
--------------------------------------------------------------------------------
1 | Sidekiq.configure_server { |config| config.redis = { url: ENV['REDIS_URL'] } }
2 |
3 | Sidekiq.configure_client { |config| config.redis = { url: ENV['REDIS_URL'] } }
4 |
--------------------------------------------------------------------------------
/config/webpack/test.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = process.env.NODE_ENV || 'development';
2 |
3 | const environment = require('./environment');
4 |
5 | module.exports = environment.toWebpackConfig();
6 |
--------------------------------------------------------------------------------
/db/migrate/20190903193053_remove_task_section_field.rb:
--------------------------------------------------------------------------------
1 | class RemoveTaskSectionField < ActiveRecord::Migration[5.2]
2 | def change
3 | remove_column :tasks, :section, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20190913200833_add_list_number_to_tasks.rb:
--------------------------------------------------------------------------------
1 | class AddListNumberToTasks < ActiveRecord::Migration[5.2]
2 | def change
3 | add_column :tasks, :list_number, :bigint
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/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/webpack/development.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = process.env.NODE_ENV || 'development';
2 |
3 | const environment = require('./environment');
4 |
5 | module.exports = environment.toWebpackConfig();
6 |
--------------------------------------------------------------------------------
/config/webpack/production.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = process.env.NODE_ENV || 'production';
2 |
3 | const environment = require('./environment');
4 |
5 | module.exports = environment.toWebpackConfig();
6 |
--------------------------------------------------------------------------------
/spec/factories/roles.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :role do
3 | name { 'admin' }
4 |
5 | trait :super_admin do
6 | name { 'super_admin' }
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/common/NotFoundPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default function NotFound(props: {path?: string; default: boolean}) {
4 | return Page Not Found
;
5 | }
6 |
--------------------------------------------------------------------------------
/spec/factories/users.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :user do
3 | sequence(:email) { |n| Faker::Internet.email.gsub(/@/, "#{n}@") }
4 | sequence(:full_name) { Faker::Name.name }
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/spec/models/user_notification_frequency_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe UserNotificationFrequency, type: :model do
4 | pending "add some examples to (or delete) #{__FILE__}"
5 | end
6 |
--------------------------------------------------------------------------------
/lib/tasks/company.rake:
--------------------------------------------------------------------------------
1 | namespace :company do
2 | desc 'Remove Unused Companies'
3 | task remove_un_used_companies: :environment do
4 | Company::RemoveUnUsedCompaniesWorker.perform_async
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/spec/factories/file_messages.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :file_message do
3 | user_id { 1 }
4 | file_version_id { 1 }
5 | message { 'MyText' }
6 | is_public { false }
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/user/components/NotificationPane/components/Dropdown.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import clsx from 'clsx';
3 | import {Theme, makeStyles, createStyles} from '@material-ui/core/styles';
4 |
--------------------------------------------------------------------------------
/db/migrate/20190915022826_add_company_id_to_task_messages.rb:
--------------------------------------------------------------------------------
1 | class AddCompanyIdToTaskMessages < ActiveRecord::Migration[5.2]
2 | def change
3 | add_column :task_messages, :company_id, :bigint
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/spec/workers/company/company_kms_creation_worker_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 | RSpec.describe Company::CompanyKmsCreationWorker, type: :worker do
3 | pending "add some examples to (or delete) #{__FILE__}"
4 | end
5 |
--------------------------------------------------------------------------------
/db/migrate/20190708203246_create_roles.rb:
--------------------------------------------------------------------------------
1 | class CreateRoles < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :roles do |t|
4 | t.string :title
5 | t.timestamps
6 | end
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20190903100322_add_section_field_in_task.rb:
--------------------------------------------------------------------------------
1 | class AddSectionFieldInTask < ActiveRecord::Migration[5.2]
2 | def change
3 | change_table :tasks do |t|
4 | t.string :section
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/app/models/task_message.rb:
--------------------------------------------------------------------------------
1 | class TaskMessage < ApplicationRecord
2 | belongs_to :user
3 | belongs_to :task
4 | # a task message only belongs to a company if it's 'internal'
5 | belongs_to :company, optional: true
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20190817122452_add_title_to_subcription.rb:
--------------------------------------------------------------------------------
1 | class AddTitleToSubcription < ActiveRecord::Migration[5.2]
2 | def change
3 | change_table :subscriptions do |t|
4 | t.string :name
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20190904160018_add_section_id_in_task.rb:
--------------------------------------------------------------------------------
1 | class AddSectionIdInTask < ActiveRecord::Migration[5.2]
2 | def change
3 | change_table :tasks do |t|
4 | t.belongs_to :task_section
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20190904191854_adteam_id_in_lists_user.rb:
--------------------------------------------------------------------------------
1 | class AdteamIdInListsUser < ActiveRecord::Migration[5.2]
2 | def change
3 | change_table :lists_users do |t|
4 | t.belongs_to :team
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/spec/factories/file_labels.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :file_label do
3 | description { 'MyText' }
4 | file_label_color { 'MyString' }
5 | is_active { false }
6 | is_public { false }
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/spec/workers/company/remove_un_used_companies_worker_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 | RSpec.describe Company::RemoveUnUsedCompaniesWorker, type: :worker do
3 | pending "add some examples to (or delete) #{__FILE__}"
4 | end
5 |
--------------------------------------------------------------------------------
/app/graphql/types/role_type.rb:
--------------------------------------------------------------------------------
1 | module Types
2 | class RoleType < GraphQL::Schema::Object
3 | description 'All Available Roles'
4 |
5 | field :id, ID, null: false
6 | field :name, String, null: false
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/config/boot.rb:
--------------------------------------------------------------------------------
1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
2 |
3 | require 'bundler/setup' # Set up gems listed in the Gemfile.
4 | require 'bootsnap/setup' # Speed up boot time by caching expensive operations.
5 |
--------------------------------------------------------------------------------
/config/webpack/environment.js:
--------------------------------------------------------------------------------
1 | const {environment} = require('@rails/webpacker');
2 | const typescript = require('./loaders/typescript');
3 |
4 | environment.loaders.prepend('typescript', typescript);
5 | module.exports = environment;
6 |
--------------------------------------------------------------------------------
/db/migrate/20190819141140_add_team_id_to_user_roles.rb:
--------------------------------------------------------------------------------
1 | class AddTeamIdToUserRoles < ActiveRecord::Migration[5.2]
2 | def change
3 | change_table :roles_users do |t|
4 | t.belongs_to :company
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/spec/workers/company/company_s3_bucket_creation_worker_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 | RSpec.describe Company::CompanyS3BucketCreationWorker, type: :worker do
3 | pending "add some examples to (or delete) #{__FILE__}"
4 | end
5 |
--------------------------------------------------------------------------------
/db/migrate/20190910220419_add_reviewer_type_task_owner.rb:
--------------------------------------------------------------------------------
1 | class AddReviewerTypeTaskOwner < ActiveRecord::Migration[5.2]
2 | def change
3 | change_table :task_owners do |t|
4 | t.string :owner_type
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/app/graphql/types/current_user_type.rb:
--------------------------------------------------------------------------------
1 | module Types
2 | class CurrentUserType < GraphQL::Schema::Object
3 | description 'CurrentUser'
4 |
5 | field :id, String, null: false
6 | field :user, UserType, null: true
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/app/graphql/types/user_list_type.rb:
--------------------------------------------------------------------------------
1 | module Types
2 | class UserListType < GraphQL::Schema::Object
3 | description 'CurrentUser'
4 |
5 | field :id, String, null: false
6 | field :lists, [ListType], null: true
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/config/initializers/aws.rb:
--------------------------------------------------------------------------------
1 | require 'aws-sdk'
2 | Aws.config.update(
3 | credentials:
4 | Aws::Credentials.new(
5 | ENV['AWS_ACCESS_KEY_ID'],
6 | ENV['AWS_SECRET_ACCESS_KEY']
7 | ),
8 | region: 'us-east-1'
9 | )
10 |
--------------------------------------------------------------------------------
/db/migrate/20190702001204_add_fields_to_user.rb:
--------------------------------------------------------------------------------
1 | class AddFieldsToUser < ActiveRecord::Migration[5.2]
2 | def change
3 | change_table :users do |t|
4 | t.string :first_name
5 | t.string :last_name
6 | end
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20190821153008_add_last_company_id_to_user.rb:
--------------------------------------------------------------------------------
1 | class AddLastCompanyIdToUser < ActiveRecord::Migration[5.2]
2 | def change
3 | change_table :users do |t|
4 | t.bigint :last_viewed_company_id
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20190903193648_create_task_sections.rb:
--------------------------------------------------------------------------------
1 | class CreateTaskSections < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :task_sections do |t|
4 | t.string :name
5 | t.timestamps
6 | end
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20190913165628_add_is_public_to_task.rb:
--------------------------------------------------------------------------------
1 | class AddIsPublicToTask < ActiveRecord::Migration[5.2]
2 | def change
3 | change_table :task_messages do |t|
4 | t.boolean :is_public, default: false
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/config/cable.yml:
--------------------------------------------------------------------------------
1 | development:
2 | adapter: async
3 |
4 | test:
5 | adapter: async
6 |
7 | production:
8 | adapter: redis
9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
10 | channel_prefix: prepdd_production
11 |
--------------------------------------------------------------------------------
/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 += %i[password]
5 |
--------------------------------------------------------------------------------
/db/migrate/20190911184105_add_rank_on_list.rb:
--------------------------------------------------------------------------------
1 | class AddRankOnList < ActiveRecord::Migration[5.2]
2 | def change
3 | change_table :lists do |t|
4 | t.integer :requester_rank
5 | t.integer :responder_rank
6 | end
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | require_relative '../config/boot'
8 | require 'rake'
9 | Rake.application.run
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/db/migrate/20190916060852_create_file_version_tasks.rb:
--------------------------------------------------------------------------------
1 | class CreateFileVersionTasks < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :file_version_tasks do |t|
4 | t.bigint :file_version_id
5 | t.bigint :task_id
6 | end
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20190717200222_create_teams.rb:
--------------------------------------------------------------------------------
1 | class CreateTeams < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :teams do |t|
4 | t.string :name
5 | t.boolean :is_active, default: true
6 | t.timestamps
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/db/migrate/20190708203644_create_roles_users.rb:
--------------------------------------------------------------------------------
1 | class CreateRolesUsers < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :roles_users do |t|
4 | t.belongs_to :user
5 | t.belongs_to :role
6 | t.timestamps
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/db/migrate/20190717200930_create_teams_users.rb:
--------------------------------------------------------------------------------
1 | class CreateTeamsUsers < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :teams_users do |t|
4 | t.belongs_to :user
5 | t.belongs_to :team
6 | t.timestamps
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/db/migrate/20190904104719_create_lists_users.rb:
--------------------------------------------------------------------------------
1 | class CreateListsUsers < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :lists_users do |t|
4 | t.belongs_to :user
5 | t.belongs_to :list
6 | t.timestamps
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/db/migrate/20190911145904_create_user_notification_scopes.rb:
--------------------------------------------------------------------------------
1 | class CreateUserNotificationScopes < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :user_notification_scopes do |t|
4 | t.string :description
5 | t.timestamps
6 | end
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20190911051521_create_file_bases.rb:
--------------------------------------------------------------------------------
1 | class CreateFileBases < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :file_bases do |t|
4 | t.boolean :is_active
5 | t.boolean :is_template
6 |
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/app/graphql/types/task_section_type.rb:
--------------------------------------------------------------------------------
1 | module Types
2 | class TaskSectionType < GraphQL::Schema::Object
3 | description 'TaskSection'
4 |
5 | field :id, ID, null: false
6 | field :name, String, null: true
7 | field :tasks, [TaskType], null: true
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/factories/file_versions.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :file_version do
3 | file_id { 1 }
4 | file_owner_id { 1 }
5 | version { 1 }
6 | file_name { 'MyString' }
7 | file_extension { 'MyString' }
8 | file_location { 'MyString' }
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/app/graphql/types/user_details_type.rb:
--------------------------------------------------------------------------------
1 | module Types
2 | class UserDetailsType < GraphQL::Schema::Object
3 | description 'UserDetails'
4 |
5 | field :id, String, null: false
6 | field :user, UserType, null: true
7 | field :role, RoleType, null: true
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/db/migrate/20190814110824_create_users_companies.rb:
--------------------------------------------------------------------------------
1 | class CreateUsersCompanies < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :users_companies do |t|
4 | t.belongs_to :company
5 | t.belongs_to :user
6 | t.timestamps
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/db/migrate/20190911052855_create_file_tasks.rb:
--------------------------------------------------------------------------------
1 | class CreateFileTasks < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :file_tasks do |t|
4 |
5 | t.bigint :file_version_id
6 | t.bigint :task_id
7 |
8 | t.timestamps
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20190911153424_create_user_notification_frequencies.rb:
--------------------------------------------------------------------------------
1 | class CreateUserNotificationFrequencies < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :user_notification_frequencies do |t|
4 | t.string :description
5 | t.timestamps
6 | end
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | require('postcss-import'),
4 | require('postcss-flexbugs-fixes'),
5 | require('postcss-preset-env')({
6 | autoprefixer: {
7 | flexbox: 'no-2009'
8 | },
9 | stage: 3
10 | })
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/spec/controllers/welcome_controller_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe WelcomeController do
4 | describe 'Load React App' do
5 | it 'should load React app successfully' do
6 | get :index
7 | expect(response.status).to eq(200)
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/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/webpack/loaders/typescript.js:
--------------------------------------------------------------------------------
1 | const PnpWebpackPlugin = require('pnp-webpack-plugin');
2 |
3 | module.exports = {
4 | test: /\.(ts|tsx)?(\.erb)?$/,
5 | use: [
6 | {
7 | loader: 'ts-loader',
8 | options: PnpWebpackPlugin.tsLoaderOptions(),
9 | },
10 | ],
11 | };
12 |
--------------------------------------------------------------------------------
/db/migrate/20190817111651_add_company_settings.rb:
--------------------------------------------------------------------------------
1 | class AddCompanySettings < ActiveRecord::Migration[5.2]
2 | change_table :companies do |t|
3 | t.boolean :auto_pdf, default: false
4 | t.boolean :auto_watermark, default: false
5 | t.boolean :preview_only, default: false
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/app/graphql/types/company_users_type.rb:
--------------------------------------------------------------------------------
1 | module Types
2 | class CompanyUsersType < GraphQL::Schema::Object
3 | description 'CompanyUsers'
4 |
5 | field :id, ID, null: false
6 |
7 | field :company, CompanyType, null: false
8 | field :users, [UserType], null: true
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/app/models/roles_user.rb:
--------------------------------------------------------------------------------
1 | class RolesUser < ApplicationRecord
2 | belongs_to :role
3 | belongs_to :user
4 | belongs_to :company
5 |
6 | validates :user_id,
7 | uniqueness: {
8 | scope: :company_id, message: 'should have one role per company'
9 | }
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20190712213325_add_uuid_to_users_for_omani_auth.rb:
--------------------------------------------------------------------------------
1 | class AddUuidToUsersForOmaniAuth < ActiveRecord::Migration[5.2]
2 | def change
3 | change_table :users do |t|
4 | t.string :uuid
5 | t.string :token_id
6 | t.string :social_login_provider
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/db/migrate/20190824162739_create_parent_companies.rb:
--------------------------------------------------------------------------------
1 | class CreateParentCompanies < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :parent_companies do |t|
4 | t.belongs_to :child_company
5 | t.belongs_to :parent_company
6 | t.timestamps
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path('../spring', __FILE__)
4 | rescue LoadError => e
5 | raise unless e.message.include?('spring')
6 | end
7 | APP_PATH = File.expand_path('../config/application', __dir__)
8 | require_relative '../config/boot'
9 | require 'rails/commands'
10 |
--------------------------------------------------------------------------------
/config/storage.yml:
--------------------------------------------------------------------------------
1 | local:
2 | service: Disk
3 | root: <%= Rails.root.join("storage") %>
4 |
5 | amazon:
6 | service: "S3"
7 | access_key_id: <%= ENV.fetch('AWS_ACCESS_KEY_ID') %>
8 | secret_access_key: <%= ENV.fetch('AWS_SECRET_ACCESS_KEY') %>
9 | bucket: "main-prepdd"
10 | region: "us-east-1"
11 |
--------------------------------------------------------------------------------
/db/migrate/20190730211803_add_s3_bucket_location_to_company.rb:
--------------------------------------------------------------------------------
1 | class AddS3BucketLocationToCompany < ActiveRecord::Migration[5.2]
2 | def change
3 | change_table :companies do |t|
4 | t.string :s3_location
5 | t.string :kms_key_id
6 | t.string :kms_key
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/db/migrate/20190824161311_create_broker_companies.rb:
--------------------------------------------------------------------------------
1 | class CreateBrokerCompanies < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :broker_companies do |t|
4 | t.belongs_to :child_broker
5 | t.belongs_to :parent_broker
6 |
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20190909181608_create_task_owners.rb:
--------------------------------------------------------------------------------
1 | class CreateTaskOwners < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :task_owners do |t|
4 | t.belongs_to :task
5 | t.references :task_ownerable, polymorphic: true
6 |
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20190911154027_create_task_messages.rb:
--------------------------------------------------------------------------------
1 | class CreateTaskMessages < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :task_messages do |t|
4 | t.belongs_to :user
5 | t.belongs_to :task
6 | t.text :message
7 |
8 | t.timestamps
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 | <%= yield %>
12 |
13 |
14 |
--------------------------------------------------------------------------------
/db/data/20190708204424_add_basic_roles.rb:
--------------------------------------------------------------------------------
1 | class AddBasicRoles < ActiveRecord::Migration[5.2]
2 | def up
3 | Role.add('SuperAdmin')
4 | Role.add('Admin')
5 | Role.add('Owner')
6 | Role.add('Manager')
7 | Role.add('User')
8 | end
9 |
10 | def down
11 | Role.delete_all
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/app/graphql/types/search_company_users_type.rb:
--------------------------------------------------------------------------------
1 | module Types
2 | class SearchCompanyUsersType < GraphQL::Schema::Object
3 | description 'Search users by company id'
4 |
5 | field :id, String, null: false
6 | field :users, [UserType], null: true
7 | field :teams, [TeamType], null: true
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/queries/AllRoles.ts:
--------------------------------------------------------------------------------
1 | import {createQueryHook, gql} from '../graphqlHelpers';
2 | import {AllRoles} from './__generated__/AllRoles';
3 |
4 | export const useAllRoles = createQueryHook(gql`
5 | query AllRoles {
6 | roles {
7 | id
8 | name
9 | }
10 | }
11 | `);
12 |
--------------------------------------------------------------------------------
/app/graphql/types/file_base_type.rb:
--------------------------------------------------------------------------------
1 | module Types
2 | class FileBaseType < GraphQL::Schema::Object
3 | description 'A logical container for many versions of a file.'
4 |
5 | field :id, String, null: false
6 | field :is_template, Boolean, null: true
7 | field :is_active, Boolean, null: true
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/file/FilesPage/FilesPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Header from './components/Header';
4 | import Body from './components/Body';
5 |
6 | export default function FilesPage() {
7 | return (
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/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_relative 'config/application'
5 | require 'graphql/rake_task'
6 |
7 | Rails.application.load_tasks
8 |
9 | GraphQL::RakeTask.new(schema_name: 'PrepddSchema')
--------------------------------------------------------------------------------
/db/migrate/20190710202528_add_user_association_with_company.rb:
--------------------------------------------------------------------------------
1 | class AddUserAssociationWithCompany < ActiveRecord::Migration[5.2]
2 | def change
3 | change_table :companies do |t|
4 | t.belongs_to :owner
5 | end
6 |
7 | change_table :users do |t|
8 | t.belongs_to :company
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/app/graphql/types/validation_error.rb:
--------------------------------------------------------------------------------
1 | class Types::UserError < GraphQL::Schema::Object
2 | description 'A user-readable error'
3 |
4 | field :message, String, null: false, description: 'A description of the error'
5 | field :path,
6 | [String],
7 | null: true, description: 'Which input value this error came from'
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20190911052002_create_file_message_alerts.rb:
--------------------------------------------------------------------------------
1 | class CreateFileMessageAlerts < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :file_message_alerts do |t|
4 | t.integer :file_message_id
5 | t.integer :user_id
6 | t.boolean :is_read
7 |
8 | t.timestamps
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/route/team.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Switch, Route} from 'react-router-dom';
3 | import ManagementPage from '../team';
4 |
5 | export default function Router() {
6 | return (
7 |
8 |
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/route/user.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Switch, Route} from 'react-router-dom';
3 | import ProfilePage from '../user';
4 |
5 | export default function UserRoute() {
6 | return (
7 |
8 |
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/task/CreateTaskPage/CreateTaskPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Header from './components/Header';
4 | import Body from './components/Body';
5 |
6 | export default function CreateTaskPage() {
7 | return (
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/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/graphql/types/form_error_type.rb:
--------------------------------------------------------------------------------
1 | class Types::FormErrorType < GraphQL::Schema::Object
2 | description 'A user-readable error from a form field'
3 |
4 | field :message, String, null: false, description: 'A description of the error'
5 | field :path,
6 | String,
7 | null: true, description: 'Which field this error came from'
8 | end
9 |
--------------------------------------------------------------------------------
/app/graphql/types/search_companies_type.rb:
--------------------------------------------------------------------------------
1 | module Types
2 | class SearchCompaniesType < GraphQL::Schema::Object
3 | description 'Search companies by company name or user name & email'
4 |
5 | field :id, String, null: false
6 | field :users, [UserType], null: true
7 | field :companies, [CompanyType], null: true
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/route/list.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Switch, Route} from 'react-router-dom';
3 | import ListPage from '../list/ListPage';
4 |
5 | export default function ListRoute() {
6 | return (
7 |
8 |
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/route/task.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Switch, Route} from 'react-router-dom';
3 | import TaskPage from '../task/TaskPage';
4 |
5 | export default function TaskRoute() {
6 | return (
7 |
8 |
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/db/migrate/20190911051917_create_file_labels.rb:
--------------------------------------------------------------------------------
1 | class CreateFileLabels < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :file_labels do |t|
4 | t.text :description
5 | t.string :file_label_color
6 | t.boolean :is_active
7 | t.boolean :is_public
8 |
9 | t.timestamps
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20190911051944_create_file_messages.rb:
--------------------------------------------------------------------------------
1 | class CreateFileMessages < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :file_messages do |t|
4 | t.integer :user_id
5 | t.integer :file_version_id
6 | t.text :message
7 | t.boolean :is_public
8 |
9 | t.timestamps
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/bin/yarn:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | APP_ROOT = File.expand_path('..', __dir__)
3 | Dir.chdir(APP_ROOT) do
4 | begin
5 | exec "yarnpkg", *ARGV
6 | rescue Errno::ENOENT
7 | $stderr.puts "Yarn executable was not detected in the system."
8 | $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
9 | exit 1
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20190911155050_create_task_message_alerts.rb:
--------------------------------------------------------------------------------
1 | class CreateTaskMessageAlerts < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :task_message_alerts do |t|
4 | t.belongs_to :task_message
5 | t.belongs_to :user
6 | t.boolean :is_read, default: false
7 |
8 | t.timestamps
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/app/graphql/types/task_message_alert_type.rb:
--------------------------------------------------------------------------------
1 | module Types
2 | class TaskMessageAlertType < GraphQL::Schema::Object
3 | description 'TaskMessageAlert'
4 |
5 | field :id, ID, null: false
6 | field :user, UserType, null: false
7 | field :taskMessage_, TaskMessage, null: false
8 | field :isRead, Boolean, null: false
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/app/graphql/types/team_type.rb:
--------------------------------------------------------------------------------
1 | module Types
2 | class TeamType < GraphQL::Schema::Object
3 | description 'Team'
4 |
5 | field :id, ID, null: false
6 | field :companyId, ID, null: false
7 | field :name, String, null: false
8 | field :users, [UserType], null: false
9 | field :company, CompanyType, null: false
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20190706032837_add_full_name_to_user.rb:
--------------------------------------------------------------------------------
1 | class AddFullNameToUser < ActiveRecord::Migration[5.2]
2 | def change
3 | change_table :users do |t|
4 | t.string :full_name, null: false, default: ''
5 | t.string :display_name, null: false, default: ''
6 | t.remove :first_name
7 | t.remove :last_name
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/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/javascript/src/modules/list/ListPage/components/styled/index.tsx:
--------------------------------------------------------------------------------
1 | import StyledButton from './StyledButton';
2 | import StyledTab from './StyledTab';
3 | import StyledTableCell from './StyledTableCell';
4 | import StyledTableRow from './StyledTableRow';
5 | import StyledTabs from './StyledTabs';
6 |
7 | export {StyledButton, StyledTab, StyledTableCell, StyledTableRow, StyledTabs};
8 |
--------------------------------------------------------------------------------
/db/migrate/20190731170005_add_sessions_table.rb:
--------------------------------------------------------------------------------
1 | class AddSessionsTable < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :sessions do |t|
4 | t.string :session_id, :null => false
5 | t.text :data
6 | t.timestamps
7 | end
8 |
9 | add_index :sessions, :session_id, :unique => true
10 | add_index :sessions, :updated_at
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/app/controllers/api_controller.rb:
--------------------------------------------------------------------------------
1 | class ApiController < ActionController::Base
2 | before_action :authenticate
3 |
4 | def authenticate
5 | api_key = request.headers['X-Api-Key']
6 | if api_key.present? && api_key == 'jKXFpXpMXYeeI0aCPfh14w'
7 | true
8 | else
9 | render json: { error: 'Invalid Api-Key' }, status: :unauthorized
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20190708151108_create_companies.rb:
--------------------------------------------------------------------------------
1 | class CreateCompanies < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :companies do |t|
4 | t.string :name
5 | t.bigint :parent_id
6 | t.bigint :broker_co_id
7 | t.bigint :subscription_id
8 | t.boolean :is_active
9 | t.string :encryption_key
10 |
11 | t.timestamps
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/SignOutUser.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {SignOutUser} from './__generated__/SignOutUser';
3 |
4 | export const useSignOutUser = createMutationHook(gql`
5 | mutation SignOutUser {
6 | signOutUser {
7 | errors {
8 | path
9 | message
10 | }
11 | success
12 | }
13 | }
14 | `);
15 |
--------------------------------------------------------------------------------
/app/javascript/src/helpers/queries.ts:
--------------------------------------------------------------------------------
1 | import {gql} from 'apollo-boost';
2 |
3 | export const SEARCH_COMPANY_USERS = gql`
4 | query SearchCompanyUsers($text: String!, $companyId: ID!) {
5 | searchCompanyUsers(text: $text, companyId: $companyId) {
6 | users {
7 | id
8 | email
9 | fullName
10 | profileUrl
11 | }
12 | teams {
13 | id
14 | name
15 | }
16 | }
17 | }
18 | `;
--------------------------------------------------------------------------------
/app/javascript/src/modules/route/company.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Switch, Route} from 'react-router-dom';
3 | import SubscriptionPage from '../company/CompanySubscription';
4 | import SettingsPage from '../company';
5 |
6 | export default function CompanyRoute() {
7 | return (
8 |
9 |
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/db/migrate/20190911052305_create_file_versions.rb:
--------------------------------------------------------------------------------
1 | class CreateFileVersions < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :file_versions do |t|
4 | t.integer :file_id
5 | t.integer :file_owner_id
6 | t.integer :version
7 | t.string :file_name
8 | t.string :file_extension
9 | t.string :file_location
10 |
11 | t.timestamps
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/spec/support/graphql_spec_helper.rb:
--------------------------------------------------------------------------------
1 | module GraphqlSpecHelper
2 | def graphql!
3 | PrepddSchema.execute(@query, context: @context, variables: @variables)
4 | end
5 |
6 | def prepare_query_variables(variables)
7 | @variables = variables
8 | end
9 |
10 | def prepare_context(context)
11 | @context = context
12 | end
13 |
14 | def prepare_query(query)
15 | @query = query
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Prepdd
5 |
6 | <%= csrf_meta_tags %>
7 | <%= csp_meta_tag %>
8 | <%= javascript_pack_tag 'application_pack' %>
9 |
10 |
11 |
12 | <%= yield %>
13 |
14 |
15 |
--------------------------------------------------------------------------------
/db/migrate/20190830185711_create_tasks.rb:
--------------------------------------------------------------------------------
1 | class CreateTasks < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :tasks do |t|
4 | t.string :name
5 | t.string :description
6 | t.integer :priority, default: 0
7 | t.integer :status, default: 0
8 | t.datetime :due_date
9 | t.boolean :is_active
10 | t.belongs_to :list
11 |
12 | t.timestamps
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/app/javascript/src/constants/theme.ts:
--------------------------------------------------------------------------------
1 | export const COLORS = {
2 | background: '#FFFFFF',
3 | primary: '#3A84FF',
4 | primaryHover: '#EBF2FF',
5 | };
6 |
7 | export const FONT = {
8 | color: '#2C2C2C',
9 | family: 'Montserrat',
10 | weight: {
11 | bold: 800,
12 | regular: 600,
13 | },
14 | size: {
15 | xs: '12px',
16 | sm: '15px',
17 | md: '18px',
18 | lg: '24px',
19 | xl: '30px',
20 | },
21 | };
22 |
--------------------------------------------------------------------------------
/app/graphql/mutations/delete_task_message.rb:
--------------------------------------------------------------------------------
1 | class Mutations::DeleteTaskMessage < GraphQL::Schema::Mutation
2 | argument :id, ID, required: true
3 |
4 | field :errors, [Types::FormErrorType], null: false
5 | field :success, Boolean, null: false
6 |
7 | def resolve(id: nil, message: nil)
8 | response = { errors: [] }
9 |
10 | TaskMessage.find(id).destroy!
11 |
12 | response[:success] = true
13 | response
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/db/migrate/20190830182008_create_lists.rb:
--------------------------------------------------------------------------------
1 | class CreateLists < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :lists do |t|
4 | t.string :name
5 | t.string :description
6 | t.boolean :is_active, default: true
7 | t.boolean :is_template
8 | t.boolean :is_public_template
9 | t.belongs_to :requester
10 | t.belongs_to :responder
11 |
12 | t.timestamps
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/app/graphql/mutations/delete_lists.rb:
--------------------------------------------------------------------------------
1 | class Mutations::DeleteLists < GraphQL::Schema::Mutation
2 | argument :listIds, [ID], required: true
3 |
4 | field :errors, [Types::FormErrorType], null: false
5 | field :success, Boolean, null: false
6 |
7 | def resolve(list_ids: nil)
8 | response = { errors: [] }
9 |
10 | list_ids.each { |id| List.find(id).destroy! }
11 |
12 | response[:success] = true
13 | response
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/company/components/FormPanel/components/StyledTableRow.tsx:
--------------------------------------------------------------------------------
1 | import {withStyles} from '@material-ui/core/styles';
2 | import TableRow from '@material-ui/core/TableRow';
3 |
4 | const StyledTableRow = withStyles({
5 | root: {
6 | height: '60px',
7 | fontFamily: 'Montserrat',
8 | fontWeight: 600,
9 | fontSize: '15px',
10 | color: '#2C2C2C',
11 | },
12 | })(TableRow);
13 |
14 | export default StyledTableRow;
15 |
--------------------------------------------------------------------------------
/spec/models/user_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe User, type: :model do
4 | describe '#associations' do
5 | it { should have_many :owned_companies }
6 | it { should have_many :roles }
7 | it { should have_many :roles_users }
8 | it { should have_many :teams }
9 | it { should have_many :teams_users }
10 | it { should have_many :users_companies }
11 | it { should have_many :companies }
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/queries/UserLists.ts:
--------------------------------------------------------------------------------
1 | import {createQueryHook, gql} from '../graphqlHelpers';
2 | import {UserLists} from './__generated__/UserLists';
3 |
4 | export const useUserLists = createQueryHook(gql`
5 | query UserLists {
6 | userLists {
7 | id
8 | lists {
9 | id
10 | name
11 | sections {
12 | id
13 | name
14 | }
15 | }
16 | }
17 | }
18 | `);
19 |
--------------------------------------------------------------------------------
/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| line =~ /my_noisy_library/ }
5 |
6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7 | # Rails.backtrace_cleaner.remove_silencers!
8 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/list/ListPage/components/styled/StyledTabs.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {withStyles} from '@material-ui/core/styles';
3 | import Tabs from '@material-ui/core/Tabs';
4 |
5 | const StyledTabs = withStyles({
6 | root: {
7 | borderBottom: '1px solid #D8D8D8',
8 | },
9 | indicator: {
10 | backgroundColor: '#3A84FF',
11 | borderRadius: '3px 3px 0 0',
12 | },
13 | })(Tabs);
14 |
15 | export default StyledTabs;
16 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/DeleteTasks.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {deleteTasks, deleteTasksVariables} from './__generated__/deleteTasks';
3 |
4 | const deleteTasks = createMutationHook(gql`
5 | mutation deleteTasks($taskIds: [ID!]!) {
6 | deleteTasks(taskIds: $taskIds) {
7 | success
8 | taskIds
9 | }
10 | }
11 | `);
12 |
13 | export default deleteTasks;
14 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/list/ListPage/components/styled/StyledTableCell.tsx:
--------------------------------------------------------------------------------
1 | import {withStyles} from '@material-ui/core/styles';
2 | import TableCell from '@material-ui/core/TableCell';
3 |
4 | const StyledTableCell = withStyles({
5 | root: {
6 | padding: '0px 24px 0px 24px',
7 | fontFamily: 'Montserrat',
8 | fontSize: '12px',
9 | fontWeight: 600,
10 | color: '#606060',
11 | },
12 | })(TableCell);
13 |
14 | export default StyledTableCell;
15 |
--------------------------------------------------------------------------------
/db/migrate/20190726063616_create_subscriptions.rb:
--------------------------------------------------------------------------------
1 | class CreateSubscriptions < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :subscriptions do |t|
4 | t.string :description
5 | t.integer :max_users
6 | t.integer :max_storage
7 | t.integer :additional_storage
8 | t.boolean :auto_pdf
9 | t.boolean :auto_watermark
10 | t.boolean :modify_subscription
11 |
12 | t.timestamps
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/app/models/team.rb:
--------------------------------------------------------------------------------
1 | class Team < ApplicationRecord
2 | has_many :teams_users
3 | has_many :users, through: :teams_users
4 | belongs_to :company
5 |
6 | has_many :lists_users
7 | has_many :lists, through: :lists_users
8 |
9 | has_many :task_owners, as: :task_ownerable
10 | has_many :owned_team_tasks,
11 | class_name: 'Task',
12 | through: :task_owners,
13 | source: :task_ownerable,
14 | source_type: 'Team'
15 | end
16 |
--------------------------------------------------------------------------------
/config/credentials.yml.enc:
--------------------------------------------------------------------------------
1 | cIz/VrI4GAZa6tmUsqo/SWTpwexvyHuH1A/nSV1O3Afy/Ge47BQ2PA0hDlfYnm0bH5JlKvcWFeqyuQbbxLAI9j5zVvD6IvwFXLYIhESq2sfXbCbqdhSoHvviMGk2M/hH+qY2kWUNJotnk8bhaUXpGgHYV38G0m75MDDS0zNZDQlwNI07RwS2jTNxREgKuii2GvJQpTJpFh1w2bt93BfZC8adMrNFtfJKjRORBveZMpebtnzOdknCVpAFSau7fMFfaUv+daeFaEo+Al9c1B/vl0mJROZGzxfXac/lU04ZXcCYDrZCpmRcKR4oYIiCY8Woyemt89qVWnt45ygKteLcGOmFEiZPA7F8hkvms8S/cY4G0reOMlnOlwgGJA3v2VA6YNIONYax/zSHJFp8hOl4QQiBKya8h1P9NP8U--9vHccA8EdZrW9dvX--etz2jif3ZsuCWusIL5EbZg==
--------------------------------------------------------------------------------
/app/graphql/types/subscription_type.rb:
--------------------------------------------------------------------------------
1 | module Types
2 | class SubscriptionType < GraphQL::Schema::Object
3 | field :id, ID, null: false
4 | field :name, String, null: false
5 | field :description, String, null: true
6 | field :max_users, String, null: true
7 | field :max_storage, String, null: true
8 | field :additional_storage, String, null: true
9 | field :auto_pdf, Boolean, null: true
10 | field :auto_watermark, Boolean, null: true
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/company/components/FormPanel/components/StyledTableCell.tsx:
--------------------------------------------------------------------------------
1 | import {withStyles} from '@material-ui/core/styles';
2 | import TableCell from '@material-ui/core/TableCell';
3 |
4 | const StyledTableCell = withStyles({
5 | root: {
6 | height: '60px',
7 | padding: '0px',
8 | fontFamily: 'Montserrat',
9 | fontSize: '15px',
10 | fontWeight: 600,
11 | color: '#2C2C2C',
12 | },
13 | })(TableCell);
14 |
15 | export default StyledTableCell;
16 |
--------------------------------------------------------------------------------
/app/graphql/types/user_for_password_reset_type.rb:
--------------------------------------------------------------------------------
1 | module Types
2 | class UserForPasswordResetType < GraphQL::Schema::Object
3 | description 'User with limited fields for the password reset screen'
4 |
5 | field :email, String, null: false
6 | field :reset_password_period_valid,
7 | Boolean,
8 | null: true, method: :reset_password_period_valid?
9 |
10 | def email
11 | object.email if object.reset_password_period_valid?
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/app/javascript/src/helpers/roleHelpers.ts:
--------------------------------------------------------------------------------
1 | export const isSuperAdmin = (role: string) => role === 'SuperAdmin';
2 |
3 | export const isAdmin = (role: string) => role === 'Admin';
4 |
5 | export const isOwner = (role: string) => role === 'Owner';
6 |
7 | export const isManager = (role: string) => role === 'Manager';
8 |
9 | export const isUser = (role: string) => role === 'User';
10 |
11 | export const canBeAdmin = (role: string) =>
12 | isSuperAdmin(role) || isAdmin(role) || isOwner(role);
13 |
--------------------------------------------------------------------------------
/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', URI::HTTP.build(host: URI.parse(root_url).host, path: "/reset_password/#{@token}").to_s %>
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/graphql/types/task_attributes.rb:
--------------------------------------------------------------------------------
1 | class Types::TaskAttributes < Types::BaseInputObject
2 | description 'Attributes for creating or updating a task'
3 |
4 | argument :name, String, required: true
5 | argument :description, String, required: true
6 | argument :priority, String, required: true
7 | argument :status, String, required: true
8 | argument :due_date, String, required: true
9 | argument :section, String, required: true
10 | argument :isActive, Boolean, required: true
11 | end
12 |
--------------------------------------------------------------------------------
/app/models/role.rb:
--------------------------------------------------------------------------------
1 | class Role < ApplicationRecord
2 | has_many :roles_users
3 | has_many :users, through: :roles_users
4 |
5 | before_validation :customize_title
6 | validates :name, uniqueness: true
7 |
8 | def customize_title(role_name = name)
9 | self.name = role_name.camelize.titlecase.gsub(/\s+/, '')
10 | end
11 |
12 | def self.add(name)
13 | where(name: name).first_or_create
14 | rescue StandardError
15 | raise ArgumentError, 'Argument title not valid.'
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/db/migrate/20190715093652_add_bio_and_notification_fields_to_user.rb:
--------------------------------------------------------------------------------
1 | class AddBioAndNotificationFieldsToUser < ActiveRecord::Migration[5.2]
2 | def change
3 | change_table :users do |t|
4 | t.belongs_to :notification
5 | t.integer :notification_scope
6 | t.integer :notification_frequency
7 | t.datetime :notification_time
8 | t.datetime :notification_day
9 | t.integer :active_state_id
10 | t.string :user_token
11 | t.string :bio
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/app/controllers/api/tasks_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::TasksController < ApplicationController
2 | skip_before_action :verify_authenticity_token
3 |
4 | def import_task
5 | status = true
6 | begin
7 | tasks = Task.import(task_params[:files])
8 | rescue => error
9 | Rails.logger.info error
10 | status = false
11 | end
12 | render json: { status: status, tasks: tasks }
13 | end
14 |
15 | private
16 |
17 | def task_params
18 | params.permit(files: [])
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/bin/webpack:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
4 | ENV["NODE_ENV"] ||= "development"
5 |
6 | require "pathname"
7 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
8 | Pathname.new(__FILE__).realpath)
9 |
10 | require "rubygems"
11 | require "bundler/setup"
12 |
13 | require "webpacker"
14 | require "webpacker/webpack_runner"
15 |
16 | APP_ROOT = File.expand_path("..", __dir__)
17 | Dir.chdir(APP_ROOT) do
18 | Webpacker::WebpackRunner.run(ARGV)
19 | end
20 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/team/components/styled/StyledTableCell.tsx:
--------------------------------------------------------------------------------
1 | import {withStyles} from '@material-ui/core/styles';
2 | import TableCell from '@material-ui/core/TableCell';
3 |
4 | const StyledTableCell = withStyles({
5 | root: {
6 | padding: '6px 0px 6px 0px',
7 | fontFamily: 'Montserrat',
8 | fontSize: '12px',
9 | fontWeight: 600,
10 | color: '#606060',
11 | '&:last-child': {
12 | paddingRight: '0px',
13 | },
14 | },
15 | })(TableCell);
16 |
17 | export default StyledTableCell;
18 |
--------------------------------------------------------------------------------
/config/database.yml:
--------------------------------------------------------------------------------
1 | default: &default
2 | adapter: postgresql
3 | encoding: unicode
4 | pool: 5
5 |
6 | development:
7 | <<: *default
8 | database: prepdd_development
9 |
10 | production:
11 | <<: *default
12 | url: <%= ENV['DATABASE_URL'] %>
13 |
14 | # Warning: The database defined as "test" will be erased and
15 | # re-generated from your development database when you run "rake".
16 | # Do not set this db to the same as development or production.
17 | test:
18 | <<: *default
19 | database: prepdd_test
20 |
--------------------------------------------------------------------------------
/bin/webpack-dev-server:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
4 | ENV["NODE_ENV"] ||= "development"
5 |
6 | require "pathname"
7 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
8 | Pathname.new(__FILE__).realpath)
9 |
10 | require "rubygems"
11 | require "bundler/setup"
12 |
13 | require "webpacker"
14 | require "webpacker/dev_server_runner"
15 |
16 | APP_ROOT = File.expand_path("..", __dir__)
17 | Dir.chdir(APP_ROOT) do
18 | Webpacker::DevServerRunner.run(ARGV)
19 | end
20 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/CreateTask.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {CreateTask, CreateTaskVariables} from './__generated__/CreateTask';
3 |
4 | export const useCreateTask = createMutationHook<
5 | CreateTask,
6 | CreateTaskVariables
7 | >(gql`
8 | mutation CreateTask($listId: ID!, $tasks: [TaskAttributes!]!) {
9 | createTask(listId: $listId, tasks: $tasks) {
10 | errors {
11 | path
12 | message
13 | }
14 | success
15 | }
16 | }
17 | `);
18 |
--------------------------------------------------------------------------------
/app/graphql/types/roles_user_type.rb:
--------------------------------------------------------------------------------
1 | module Types
2 | class RolesUserType < GraphQL::Schema::Object
3 | description 'All Available Roles of User'
4 |
5 | field :id, ID, null: false
6 | field :name, String, null: false
7 | field :companyId, ID, null: false
8 |
9 | def id
10 | object.role.id
11 | end
12 |
13 | def name
14 | object.role.name
15 | end
16 |
17 | def name
18 | object.role.name
19 | end
20 |
21 | def company_id
22 | object.company_id
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/queries/AllTemplates.ts:
--------------------------------------------------------------------------------
1 | import {createQueryHook, gql} from '../graphqlHelpers';
2 | import {AllTemplates} from './__generated__/AllTemplates';
3 |
4 | export const useAllTemplates = createQueryHook(gql`
5 | query AllTemplates {
6 | templateLists {
7 | id
8 | name
9 | tasks {
10 | id
11 | name
12 | section {
13 | id
14 | name
15 | }
16 | description
17 | priority
18 | status
19 | }
20 | }
21 | }
22 | `);
23 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/queries/UserForPasswordReset.ts:
--------------------------------------------------------------------------------
1 | import {createQueryHook, gql} from '../graphqlHelpers';
2 | import {
3 | UserForPasswordReset,
4 | UserForPasswordResetVariables,
5 | } from './__generated__/UserForPasswordReset';
6 |
7 | export const useUserForPasswordReset = createQueryHook<
8 | UserForPasswordReset,
9 | UserForPasswordResetVariables
10 | >(gql`
11 | query UserForPasswordReset($token: String!) {
12 | userForPasswordReset(token: $token) {
13 | email
14 | resetPasswordPeriodValid
15 | }
16 | }
17 | `);
18 |
--------------------------------------------------------------------------------
/app/workers/company/company_s3_bucket_creation_worker.rb:
--------------------------------------------------------------------------------
1 | class Company::CompanyS3BucketCreationWorker
2 | include Sidekiq::Worker
3 |
4 | def perform(company_id)
5 | require 'aws-sdk-s3'
6 |
7 | company = Company.find(company_id)
8 | if company && !company.s3_location
9 | s3 = Aws::S3::Client.new
10 | bucket = s3.create_bucket(bucket: company.name.downcase + "-prepdd-" + Rails.env)
11 |
12 | if bucket
13 | company.s3_location = bucket.location
14 | company.save!
15 | end
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/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) { wrap_parameters format: %i[json] }
8 |
9 | # To enable root element in JSON for ActiveRecord objects.
10 | # ActiveSupport.on_load(:active_record) do
11 | # self.include_root_in_json = true
12 | # end
13 |
--------------------------------------------------------------------------------
/app/graphql/mutations/delete_tasks.rb:
--------------------------------------------------------------------------------
1 | class Mutations::DeleteTasks < GraphQL::Schema::Mutation
2 | argument :taskIds, [ID], required: true
3 |
4 | field :errors, [Types::FormErrorType], null: false
5 | field :success, Boolean, null: false
6 | field :task_ids, [ID], null: false
7 |
8 | def resolve(task_ids: nil)
9 | response = { errors: [] }
10 |
11 | task_ids.each { |id| Task.find(id).destroy! }
12 |
13 | response[:success] = true
14 | # returning task ids to update the DOM
15 | response[:task_ids] = task_ids
16 | response
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/app/graphql/mutations/sign_out_user.rb:
--------------------------------------------------------------------------------
1 | class Mutations::SignOutUser < GraphQL::Schema::Mutation
2 | field :errors, [Types::FormErrorType], null: false
3 | field :success, Boolean, null: false
4 |
5 | def resolve
6 | response = { errors: [] }
7 |
8 | unless context[:controller].user_signed_in?
9 | response[:errors].push({ path: 'root', message: 'Already signed out.' })
10 | response[:success] = false
11 | return response
12 | end
13 |
14 | context[:controller].sign_out
15 | response[:success] = true
16 | response
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/bin/spring:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # This file loads Spring without using Bundler, in order to be fast.
4 | # It gets overwritten when you run the `spring binstub` command.
5 |
6 | unless defined?(Spring)
7 | require 'rubygems'
8 | require 'bundler'
9 |
10 | lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read)
11 | spring = lockfile.specs.detect { |spec| spec.name == 'spring' }
12 | if spring
13 | Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path
14 | gem 'spring', spring.version
15 | require 'spring/binstub'
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/app/models/list.rb:
--------------------------------------------------------------------------------
1 | class List < ApplicationRecord
2 | belongs_to :requester,
3 | class_name: 'Company', foreign_key: 'requester_id', optional: true
4 | belongs_to :responder,
5 | class_name: 'Company', foreign_key: 'responder_id', optional: true
6 |
7 | has_many :tasks
8 | has_many :lists_users
9 | has_many :owners, class_name: 'User', through: :lists_users, source: :user
10 |
11 | after_create :add_rank
12 |
13 | def add_rank
14 | self.responder_rank = self.id
15 | self.requester_rank = self.id
16 | self.save!
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/queries/__generated__/AllRoles.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL query operation: AllRoles
7 | // ====================================================
8 |
9 | export interface AllRoles_roles {
10 | __typename: "Role";
11 | id: string;
12 | name: string;
13 | }
14 |
15 | export interface AllRoles {
16 | /**
17 | * Return All available roles
18 | */
19 | roles: AllRoles_roles[];
20 | }
21 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/CreateCompany.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {
3 | CreateCompany,
4 | CreateCompanyVariables,
5 | } from './__generated__/CreateCompany';
6 |
7 | export const useCompanyCreate = createMutationHook<
8 | CreateCompany,
9 | CreateCompanyVariables
10 | >(gql`
11 | mutation CreateCompany($name: String!) {
12 | createCompany(name: $name) {
13 | company {
14 | name
15 | }
16 | errors {
17 | path
18 | message
19 | }
20 | success
21 | }
22 | }
23 | `);
24 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/layout/components/TopBar/components/StyledBadge.tsx:
--------------------------------------------------------------------------------
1 | import {withStyles} from '@material-ui/core/styles';
2 | import Badge from '@material-ui/core/Badge';
3 |
4 | const StyledBadge = withStyles({
5 | badge: {
6 | top: '15%',
7 | right: '6px',
8 | minWidth: '15px',
9 | height: '15px',
10 | background: '#FF507C',
11 | fontFamily: 'Montserrat',
12 | fontWeight: 'bold',
13 | fontSize: '11px',
14 | color: '#FFFFFF',
15 | letterSpacing: '0',
16 | textAlign: 'center',
17 | },
18 | })(Badge);
19 |
20 | export default StyledBadge;
21 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | roots: ['/app/javascript/src'],
3 | transform: {
4 | '^.+\\.jsx?$': 'babel-jest',
5 | '^.+\\.tsx?$': 'ts-jest',
6 | },
7 | testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$',
8 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
9 | moduleNameMapper: {
10 | '\\.(svg|png|jpg)$': '/app/javascript/src/__mocks__/emptyAsset.ts',
11 | },
12 | // Setup Enzyme
13 | snapshotSerializers: ['enzyme-to-json/serializer'],
14 | setupFilesAfterEnv: ['/app/javascript/src/setupEnzyme.ts'],
15 | };
16 |
--------------------------------------------------------------------------------
/app/javascript/src/constants/types.ts:
--------------------------------------------------------------------------------
1 | export interface NotificationType {
2 | variant: 'success' | 'warning' | 'error' | 'info';
3 | message: string;
4 | }
5 |
6 | export interface ListType {
7 | name: string;
8 | description: string;
9 | requesterId: string;
10 | responderId: string;
11 | }
12 |
13 | export interface TaskType {
14 | name: string;
15 | description: string;
16 | priority: string;
17 | status: string;
18 | due_date: string;
19 | section: string;
20 | isActive: boolean;
21 | }
22 |
23 | export interface OptionType {
24 | value: string;
25 | label: string;
26 | }
27 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/queries/PublicTaskMessages.ts:
--------------------------------------------------------------------------------
1 | /* same note as the others -- keeping public and private methods
2 | * segregated */
3 | import {createQueryHook, gql} from '../graphqlHelpers';
4 | import {publicTaskMessages} from './__generated__/publicTaskMessages';
5 |
6 | const PublicTaskMessages = createQueryHook(gql`
7 | query publicTaskMessages($taskId: ID!) {
8 | publicTaskMessages(taskId: $taskId) {
9 | message
10 | user {
11 | fullName
12 | }
13 | createdAt
14 | }
15 | }
16 | `);
17 |
18 | export default PublicTaskMessages;
19 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/list/ListPage/components/styled/StyledTableRow.tsx:
--------------------------------------------------------------------------------
1 | import {withStyles} from '@material-ui/core/styles';
2 | import TableRow from '@material-ui/core/TableRow';
3 |
4 | const StyledTableRow = withStyles({
5 | root: {
6 | padding: '0px 24px 0px 24px',
7 | fontFamily: 'Montserrat',
8 | fontWeight: 600,
9 | fontSize: '12px',
10 | color: '#606060',
11 | '&$selected, &$hover:hover': {
12 | color: '#FFFFFF',
13 | background: '#EBF2FF',
14 | },
15 | },
16 | selected: {},
17 | hover: {},
18 | })(TableRow);
19 |
20 | export default StyledTableRow;
21 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/task/TaskPage/components/TaskTable/components/StyledBadge.tsx:
--------------------------------------------------------------------------------
1 | import {withStyles} from '@material-ui/core/styles';
2 | import Badge from '@material-ui/core/Badge';
3 |
4 | const StyledBadge = withStyles({
5 | badge: {
6 | top: '12%',
7 | right: '3px',
8 | minWidth: '10px',
9 | height: '10px',
10 | backgroundColor: '#6EB81D',
11 | fontFamily: 'Montserrat',
12 | fontWeight: 'bold',
13 | fontSize: '11px',
14 | color: '#FFFFFF',
15 | letterSpacing: '0',
16 | textAlign: 'center',
17 | },
18 | })(Badge);
19 |
20 | export default StyledBadge;
21 |
--------------------------------------------------------------------------------
/app/models/application_record.rb:
--------------------------------------------------------------------------------
1 | class ApplicationRecord < ActiveRecord::Base
2 | self.abstract_class = true
3 |
4 | def last_updated_at
5 | diff = Time.now - self.updated_at
6 | case diff
7 | when 0..60
8 | return 'just now'
9 | when 61..3_600
10 | diff = (diff / 60).to_i
11 | unit = 'minute'.pluralize diff
12 | when 3_601..(3_600 * 24)
13 | diff = (diff / 3_600).to_i
14 | unit = 'hour'.pluralize diff
15 | else
16 | diff = (diff / (3_600 * 24)).to_i
17 | unit = 'day'.pluralize diff
18 | end
19 | "#{diff} #{unit} ago"
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/queries/PrivateTaskMessages.ts:
--------------------------------------------------------------------------------
1 | /* Keeping Private and Public Message queries separate to
2 | * stave off mishaps */
3 | import {createQueryHook, gql} from '../graphqlHelpers';
4 | import {privateTaskMessages} from './__generated__/privateTaskMessages';
5 |
6 | const PrivateTaskMessages = createQueryHook(gql`
7 | query privateTaskMessages($taskId: ID!) {
8 | privateTaskMessages(taskId: $taskId) {
9 | message
10 | user {
11 | fullName
12 | }
13 | createdAt
14 | }
15 | }
16 | `);
17 |
18 | export default PrivateTaskMessages;
19 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/team/components/styled/StyledTableRow.tsx:
--------------------------------------------------------------------------------
1 | import {withStyles} from '@material-ui/core/styles';
2 | import TableRow from '@material-ui/core/TableRow';
3 |
4 | const StyledTableRow = withStyles({
5 | root: {
6 | height: '48px',
7 | padding: '0px 31px 0px 31px',
8 | fontFamily: 'Montserrat',
9 | fontWeight: 600,
10 | fontSize: '12px',
11 | color: '#606060',
12 | '&$selected, &$hover:hover': {
13 | color: '#FFFFFF',
14 | background: '#EBF2FF',
15 | },
16 | },
17 | selected: {},
18 | hover: {},
19 | })(TableRow);
20 |
21 | export default StyledTableRow;
22 |
--------------------------------------------------------------------------------
/spec/graphql/types/current_user_type_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 | module Types
3 | RSpec.describe CurrentUserType do
4 | set_graphql_type
5 | # avail type definer in our tests
6 | types = GraphQL::Define::TypeDefiner.instance
7 |
8 | it 'has an :id field of ID type' do
9 | # Ensure that the field id is of type String
10 | expect(subject.fields['id'].type.to_type_signature).to eq('String!')
11 | end
12 |
13 | it 'has a :user field of User type' do
14 | # Ensure the field is of User type
15 | expect(subject.fields['user'].type.to_type_signature).to eq('User')
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/UpdateUserPassword.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {
3 | UpdateUserPassword,
4 | UpdateUserPasswordVariables,
5 | } from './__generated__/UpdateUserPassword';
6 |
7 | export const useUpdateUserPassword = createMutationHook<
8 | UpdateUserPassword,
9 | UpdateUserPasswordVariables
10 | >(gql`
11 | mutation UpdateUserPassword($password: String!, $oldPassword: String!) {
12 | updateUserPassword(password: $password, oldPassword: $oldPassword) {
13 | errors {
14 | path
15 | message
16 | }
17 | success
18 | }
19 | }
20 | `);
21 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/queries/UserDetails.ts:
--------------------------------------------------------------------------------
1 | import {createQueryHook, gql} from '../graphqlHelpers';
2 | import {UserDetails} from './__generated__/UserDetails';
3 |
4 | export const useUserDetails = createQueryHook(gql`
5 | query UserDetails($id: ID!) {
6 | user(id: $id) {
7 | id
8 | email
9 | fullName
10 | profileUrl
11 | roles {
12 | id
13 | name
14 | companyId
15 | }
16 | teams {
17 | id
18 | name
19 | companyId
20 | }
21 | companies {
22 | id
23 | name
24 | logoUrl
25 | }
26 | }
27 | }
28 | `);
29 |
--------------------------------------------------------------------------------
/spec/graphql/types/form_error_type_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 | module Types
3 | RSpec.describe FormErrorType do
4 | set_graphql_type
5 | # avail type definer in our tests
6 | types = GraphQL::Define::TypeDefiner.instance
7 |
8 | it 'has an :message field of String type' do
9 | # Ensure that the field id is of type String
10 | expect(subject.fields['message'].type.to_type_signature).to eq('String!')
11 | end
12 |
13 | it 'has a :path field of String type' do
14 | # Ensure the field is of String type
15 | expect(subject.fields['path'].type.to_type_signature).to eq('String')
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/app/controllers/api/file_versions_controller.rb:
--------------------------------------------------------------------------------
1 | ### WIP #####
2 | module Api
3 | class FileVersionsController < ApiController
4 | skip_before_action :verify_authenticity_token
5 |
6 | def create
7 | ok = []
8 | @task = Task.find(file_params[:task_id])
9 | file_params[:files].each do |f|
10 | @file = FileVersion.create
11 | @file.file.attach(f)
12 | @task.file_versions << @file
13 | ok << url_for(@file.file)
14 | end
15 |
16 | render json: { success: ok }
17 | end
18 |
19 | private
20 |
21 | def file_params
22 | params.permit(:task_id, files: [])
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/app/graphql/types/task_message_type.rb:
--------------------------------------------------------------------------------
1 | module Types
2 | class TaskMessageType < GraphQL::Schema::Object
3 | description 'TaskMessage'
4 |
5 | field :id, ID, null: false
6 | field :user, UserType, null: false
7 | field :task, TaskType, null: false
8 | field :message, String, null: false
9 | field :isPublic, Boolean, null: false
10 | # Right now, we're not implementing editing on messages --
11 | # but we will, so this field name will change
12 | field :createdAt, String, null: false, method: :last_updated_at
13 | # For private messages, the message belongs to a company
14 | field :company, CompanyType, null: true
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/__generated__/deleteTasks.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL mutation operation: deleteTasks
7 | // ====================================================
8 |
9 | export interface deleteTasks_deleteTasks {
10 | __typename: "DeleteTasksPayload";
11 | success: boolean;
12 | taskIds: string[];
13 | }
14 |
15 | export interface deleteTasks {
16 | deleteTasks: deleteTasks_deleteTasks | null;
17 | }
18 |
19 | export interface deleteTasksVariables {
20 | taskIds: string[];
21 | }
22 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/SendPasswordResetInstructions.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {
3 | SendPasswordResetInstructions,
4 | SendPasswordResetInstructionsVariables,
5 | } from './__generated__/SendPasswordResetInstructions';
6 |
7 | export const useSendPasswordResetInstructions = createMutationHook<
8 | SendPasswordResetInstructions,
9 | SendPasswordResetInstructionsVariables
10 | >(gql`
11 | mutation SendPasswordResetInstructions($email: String!) {
12 | sendResetPasswordInstructions(email: $email) {
13 | errors {
14 | path
15 | message
16 | }
17 | success
18 | }
19 | }
20 | `);
21 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/user/__tests__/UserProfile.test.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import {shallow} from 'enzyme';
3 | import UserProfilePage from '../UserProfile';
4 | import ProfilePane from '../components/ProfilePane';
5 | import NotificationPane from '../components/NotificationPane';
6 |
7 | describe('User Profile Page', () => {
8 | it('renders profile pane', () => {
9 | const wrapper = shallow();
10 | expect(wrapper.find(ProfilePane).length).toBe(1);
11 | });
12 |
13 | it('renders notification pane', () => {
14 | const wrapper = shallow();
15 | expect(wrapper.find(NotificationPane).length).toBe(1);
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/workers/company/company_kms_creation_worker.rb:
--------------------------------------------------------------------------------
1 | class Company::CompanyKmsCreationWorker
2 | include Sidekiq::Worker
3 |
4 | def perform(company_id)
5 | require 'aws-sdk-kms'
6 | company = Company.find(company_id)
7 |
8 | if company && !company.kms_key_id
9 | client = Aws::KMS::Client.new
10 | kms =
11 | client.create_key(
12 | {
13 | tags: [{ tag_key: 'CompanyName', tag_value: company.name.downcase + "-prepdd-" + Rails.env }]
14 | }
15 | )
16 | end
17 |
18 | if kms
19 | company.kms_key_id = kms.key_metadata.key_id
20 | company.kms_key = kms.key_metadata.arn
21 | company.save!
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/app/graphql/mutations/update_task_message.rb:
--------------------------------------------------------------------------------
1 | class Mutations::UpdateTaskMessage < GraphQL::Schema::Mutation
2 | argument :id, ID, required: true
3 | argument :message, String, required: true
4 |
5 | field :taskMessage, Types::TaskMessageType, null: false
6 | field :errors, [Types::FormErrorType], null: false
7 | field :success, Boolean, null: false
8 |
9 | def resolve(id: nil, message: nil)
10 | response = { errors: [] }
11 |
12 | task_message = TaskMessage.find(id)
13 |
14 | task_message.update(message: message)
15 |
16 | if task_message&.persisted?
17 | response[:success] = true
18 | response[:task_message] = task_message
19 | end
20 | response
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/common/LoadingFallback.tsx:
--------------------------------------------------------------------------------
1 | import CircularProgress from '@material-ui/core/CircularProgress';
2 | import Container from '@material-ui/core/Container';
3 | import React from 'react';
4 | import {makeStyles} from '@material-ui/core/styles';
5 |
6 | const useStyles = makeStyles({
7 | box: {
8 | display: 'flex',
9 | justifyContent: 'center',
10 | alignItems: 'center',
11 | height: '80vh',
12 | },
13 | });
14 |
15 | export default function LoadingFallback() {
16 | const classes = useStyles({});
17 | return (
18 |
19 |
20 |
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/spec/models/company_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe Company, type: :model do
4 | let!(:company) { create(:company) }
5 |
6 | describe '#validations' do
7 | it { should validate_uniqueness_of(:name) }
8 | it { should validate_presence_of(:name) }
9 | end
10 |
11 | describe '#associations' do
12 | it { should have_many :users }
13 | it { should belong_to :owner }
14 | it { should belong_to :subscription }
15 | end
16 |
17 | describe '#callback' do
18 | # Company callback
19 | describe '#method' do
20 | it { is_expected.to callback(:create_s3_kms).after(:create) }
21 | it { is_expected.to callback(:generate_encryption_key).before(:create) }
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": true,
4 | "allowSyntheticDefaultImports": true,
5 | "declaration": false,
6 | "downlevelIteration": true,
7 | "esModuleInterop": true,
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "importHelpers": true,
11 | "jsx": "react",
12 | "lib": ["es6", "dom"],
13 | "module": "esnext",
14 | "moduleResolution": "node",
15 | "sourceMap": true,
16 | "strict": true,
17 | "target": "es5",
18 | "noImplicitAny": true,
19 | "typeRoots": ["node_modules/@types", "app/javascript/third_party_types"]
20 | },
21 | "exclude": ["**/*.spec.ts", "node_modules", "vendor", "public"],
22 | "compileOnSave": false
23 | }
24 |
--------------------------------------------------------------------------------
/app/controllers/api/companies_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::CompaniesController < ApiController
2 | skip_before_action :verify_authenticity_token
3 | before_action :set_company, only: %i[update_log]
4 |
5 | def update_log
6 | logo = params[:logo]
7 | if logo.content_type.in?(%['image/jpeg image/jpg image/png'])
8 | @company.logo.attach(params[:logo])
9 | render json: { status: true, logo_url: url_for(@company.logo) }
10 | else
11 | render json: { status: false, message: 'Not a valid file type' }
12 | end
13 | end
14 |
15 | private
16 |
17 | def set_company
18 | @company = Company.find(company_params[:id])
19 | end
20 |
21 | def company_params
22 | params.permit(:id, logo: [])
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/AddListOwner.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {
3 | AddListOwner,
4 | AddListOwnerVariables,
5 | } from './__generated__/AddListOwner';
6 |
7 | export const useAddListOwner = createMutationHook<
8 | AddListOwner,
9 | AddListOwnerVariables
10 | >(gql`
11 | mutation AddListOwner(
12 | $listId: ID!
13 | $companyId: ID!
14 | $userEmails: [String!]
15 | $teamIds: [ID!]
16 | ) {
17 | addListOwner(
18 | listId: $listId
19 | companyId: $companyId
20 | userEmails: $userEmails
21 | teamIds: $teamIds
22 | ) {
23 | errors {
24 | path
25 | message
26 | }
27 | success
28 | }
29 | }
30 | `);
31 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/list/ListPage/components/styled/StyledButton.tsx:
--------------------------------------------------------------------------------
1 | import {withStyles} from '@material-ui/core/styles';
2 | import Button from '@material-ui/core/Button';
3 |
4 | const StyledButton = withStyles({
5 | root: {
6 | boxSizing: 'border-box',
7 | height: '36px',
8 | minWidth: '92px',
9 | marginLeft: 20,
10 | border: '2px solid #3A84FF',
11 | borderRadius: '3px',
12 | fontFamily: 'Montserrat',
13 | fontWeight: 'bold',
14 | fontSize: '12px',
15 | color: '#3A84FF',
16 | textAlign: 'center',
17 | '&:hover': {
18 | border: '2px solid #3A84FF',
19 | },
20 | },
21 | label: {
22 | textTransform: 'capitalize',
23 | },
24 | })(Button);
25 |
26 | export default StyledButton;
27 |
--------------------------------------------------------------------------------
/app/policies/application_policy.rb:
--------------------------------------------------------------------------------
1 | class ApplicationPolicy
2 | attr_reader :user, :record
3 |
4 | def initialize(user, record)
5 | @user = user
6 | @record = record
7 | end
8 |
9 | def index?
10 | false
11 | end
12 |
13 | def show?
14 | false
15 | end
16 |
17 | def create?
18 | false
19 | end
20 |
21 | def new?
22 | create?
23 | end
24 |
25 | def update?
26 | false
27 | end
28 |
29 | def edit?
30 | update?
31 | end
32 |
33 | def destroy?
34 | false
35 | end
36 |
37 | class Scope
38 | attr_reader :user, :scope
39 |
40 | def initialize(user, scope)
41 | @user = user
42 | @scope = scope
43 | end
44 |
45 | def resolve
46 | scope.all
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "addons": ["heroku-postgresql", "heroku-redis"],
3 | "buildpacks": [
4 | {
5 | "url": "heroku/ruby"
6 | },
7 | {
8 | "url": "heroku/nodejs"
9 | }
10 | ],
11 | "env": {
12 | "HEROKU_DEBUG_RAILS_RUNNER": "1",
13 | "AWS_ACCESS_KEY_ID": {
14 | "required": true
15 | },
16 | "AWS_SECRET_ACCESS_KEY": {
17 | "required": true
18 | }
19 | },
20 | "formation": {
21 | "web": {
22 | "quantity": 1
23 | }
24 | },
25 | "name": "prepdd",
26 | "scripts": {
27 | "postdeploy": "bundle exec rake db:migrate data:migrate db:seed"
28 | },
29 | "stack": "heroku-18",
30 | "environments": {
31 | "test": {
32 | "addons": ["heroku-postgresql:in-dyno"],
33 | "env": {}
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/queries/CompanySettings.ts:
--------------------------------------------------------------------------------
1 | import {createQueryHook, gql} from '../graphqlHelpers';
2 | import {CompanySettings} from './__generated__/CompanySettings';
3 |
4 | export const useCompanySettings = createQueryHook(gql`
5 | query CompanySettings($id: ID!) {
6 | company(id: $id) {
7 | id
8 | name
9 | logoUrl
10 | parents {
11 | id
12 | name
13 | logoUrl
14 | }
15 | brokers {
16 | id
17 | name
18 | logoUrl
19 | }
20 | totalUsers
21 | totalStorage
22 | subscription {
23 | id
24 | maxUsers
25 | maxStorage
26 | }
27 | autoPdf
28 | autoWatermark
29 | previewOnly
30 | }
31 | }
32 | `);
33 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/UpdateUserData.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {
3 | UpdateUserData,
4 | UpdateUserDataVariables,
5 | } from './__generated__/UpdateUserData';
6 |
7 | export const useUpdateUserData = createMutationHook<
8 | UpdateUserData,
9 | UpdateUserDataVariables
10 | >(gql`
11 | mutation UpdateUserData(
12 | $email: String!
13 | $fullName: String!
14 | $displayName: String!
15 | $lastViewedCompanyId: ID
16 | ) {
17 | updateUserData(
18 | email: $email
19 | fullName: $fullName
20 | displayName: $displayName
21 | lastViewedCompanyId: $lastViewedCompanyId
22 | ) {
23 | errors {
24 | path
25 | message
26 | }
27 | success
28 | }
29 | }
30 | `);
31 |
--------------------------------------------------------------------------------
/lib/tasks/format.rake:
--------------------------------------------------------------------------------
1 | namespace :format do
2 | task :write do
3 | DIRECTORIES = %w[app bin config db lib spec storage test].join(',')
4 | EXTENSIONS = %w[js rake rb ts tsx].join(',')
5 |
6 | Signal.trap('INT') { exit }
7 | Signal.trap('TERM') { exit }
8 |
9 | files =
10 | Dir.glob("{#{DIRECTORIES}}/**/*.{#{EXTENSIONS}}").filter do |file|
11 | !file.include? '__generated__'
12 | end
13 |
14 | group_size = (files.size.to_f / Etc.nprocessors.to_f).ceil
15 |
16 | files.each_slice(group_size).map do |slice|
17 | spawn('./node_modules/.bin/prettier', '--write', *slice)
18 | end
19 |
20 | if Process.waitall.any? { |_pid, status| status.exitstatus != 0 }
21 | abort('Error: not all files could be formatted')
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/__generated__/globalTypes.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | //==============================================================
6 | // START Enums and Input Objects
7 | //==============================================================
8 |
9 | /**
10 | * Attributes for creating or updating a task
11 | */
12 | export interface TaskAttributes {
13 | description: string;
14 | dueDate: string;
15 | isActive: boolean;
16 | name: string;
17 | priority: string;
18 | section: string;
19 | status: string;
20 | }
21 |
22 | //==============================================================
23 | // END Enums and Input Objects
24 | //==============================================================
25 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/CreatePrivateTaskMessage.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {
3 | CreatePrivateTaskMessage,
4 | CreatePrivateTaskMessageVariables,
5 | } from './__generated__/CreatePrivateTaskMessage';
6 |
7 | const createPrivateTaskMessage = createMutationHook<
8 | CreatePrivateTaskMessage,
9 | CreatePrivateTaskMessageVariables
10 | >(gql`
11 | mutation CreatePrivateTaskMessage($taskId: ID!, $message: String!) {
12 | createTaskMessages(taskId: $taskId, message: $message, isPublic: false) {
13 | success
14 | message {
15 | id
16 | message
17 | createdAt
18 | user {
19 | fullName
20 | }
21 | }
22 | }
23 | }
24 | `);
25 |
26 | export default createPrivateTaskMessage;
27 |
--------------------------------------------------------------------------------
/spec/graphql/mutations/create_company_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 | module Mutations
3 | RSpec.describe CreateCompany, type: :request do
4 | describe 'resolve' do
5 | it 'Create new company' do
6 | company = create(:company)
7 | expect do
8 | res = post '/graphql', params: { query: query(name: company.name) }
9 | to change { Company.count }.by(1)
10 | it { expect Company.first.name.eql? company.name }
11 | end
12 | end
13 | end
14 |
15 | def query(name:)
16 | <<~GQL
17 | mutation{
18 | CreateCompany(
19 | name: #{
20 | name
21 | },
22 | ) {
23 | errors {
24 | path
25 | message
26 | }
27 | success
28 | }
29 | }
30 | GQL
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/queries/__generated__/UserForPasswordReset.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL query operation: UserForPasswordReset
7 | // ====================================================
8 |
9 | export interface UserForPasswordReset_userForPasswordReset {
10 | __typename: "UserForPasswordReset";
11 | email: string;
12 | resetPasswordPeriodValid: boolean | null;
13 | }
14 |
15 | export interface UserForPasswordReset {
16 | /**
17 | * Information for resetting a users password
18 | */
19 | userForPasswordReset: UserForPasswordReset_userForPasswordReset | null;
20 | }
21 |
22 | export interface UserForPasswordResetVariables {
23 | token: string;
24 | }
25 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/CreateList.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {CreateList, CreateListVariables} from './__generated__/CreateList';
3 |
4 | export const useCreateList = createMutationHook<
5 | CreateList,
6 | CreateListVariables
7 | >(gql`
8 | mutation CreateList(
9 | $name: String!
10 | $description: String
11 | $requesterId: ID!
12 | $responderId: ID!
13 | $tasks: [TaskAttributes!]
14 | ) {
15 | createList(
16 | name: $name
17 | description: $description
18 | requesterId: $requesterId
19 | responderId: $responderId
20 | tasks: $tasks
21 | ) {
22 | list {
23 | id
24 | name
25 | }
26 | errors {
27 | path
28 | message
29 | }
30 | success
31 | }
32 | }
33 | `);
34 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/list/ListPage/components/styled/StyledTab.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {withStyles} from '@material-ui/core/styles';
3 | import Tab from '@material-ui/core/Tab';
4 |
5 | const StyledTab = withStyles(theme => ({
6 | root: {
7 | minWidth: 36,
8 | padding: 0,
9 | fontSize: '12px',
10 | fontWeight: 'bold',
11 | color: '#606060',
12 | fontFamily: 'Montserrat',
13 | lineHeight: '20px',
14 | textTransform: 'capitalize',
15 | marginLeft: '24px',
16 | '&:hover': {
17 | color: '#40a9ff',
18 | opacity: 1,
19 | },
20 | '&$selected': {
21 | color: '#3A84FF',
22 | },
23 | '&:focus': {
24 | color: '#40a9ff',
25 | },
26 | },
27 | selected: {},
28 | }))((props: any) => );
29 |
30 | export default StyledTab;
31 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | devise_for :users, skip: :all
3 |
4 | namespace :api do
5 | post '/update_user_profile', to: 'users#update'
6 | post '/update_company_logo', to: 'companies#update_log'
7 | post '/import_task', to: 'tasks#import_task'
8 | post '/upload', to: 'file_versions#create'
9 | end
10 |
11 | require 'sidekiq/web'
12 | mount Sidekiq::Web => '/sidekiq'
13 |
14 | post '/graphql', to: 'graphql#execute'
15 | if Rails.env.development?
16 | mount GraphiQL::Rails::Engine, at: '/graphiql', graphql_path: '/graphql'
17 | end
18 |
19 | root to: 'welcome#index'
20 |
21 | # Redirect all html requests to the root so they can be handled by javascript
22 | get '*path',
23 | to: 'welcome#index',
24 | constraints: ->(request) { !request.xhr? && request.format.html? }
25 | end
26 |
--------------------------------------------------------------------------------
/app/controllers/api/users_controller.rb:
--------------------------------------------------------------------------------
1 | class Api::UsersController < ApiController
2 | skip_before_action :verify_authenticity_token
3 | before_action :set_user, only: %i[update]
4 |
5 | def update
6 | picture = params[:profile_picture]
7 | if picture.content_type.in?(%['image/jpeg image/jpg image/png'])
8 | @user.profile_picture.attach(params[:profile_picture])
9 | render json: {
10 | status: true,
11 | user: @user,
12 | profile_url: url_for(@user.profile_picture)
13 | }
14 | else
15 | render json: { status: false, message: 'Not a valid file type' }
16 | end
17 | end
18 |
19 | private
20 |
21 | def set_user
22 | @user = User.find(user_params[:id])
23 | end
24 |
25 | def user_params
26 | params.permit(:id, profile_picture: [])
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/lib/tasks/graphql.rake:
--------------------------------------------------------------------------------
1 | # This file contains our custom graphql tasks. The rest of the graphql tasks
2 | # are provided by the graphql gem
3 |
4 | namespace :graphql do
5 | desc 'Remove generated files'
6 | task :clean do
7 | rm_rf ['./__generated__', *Dir.glob('app/**/__generated__')]
8 | end
9 |
10 | desc 'Generate typescript definitions'
11 | task :types do
12 | exec(
13 | 'yarn',
14 | 'run',
15 | 'apollo',
16 | 'codegen:generate',
17 | '--localSchemaFile=schema.graphql',
18 | '--includes=app/javascript/src/**/*.{ts,tsx}',
19 | '--target=typescript',
20 | '--tagName=gql',
21 | '--globalTypesFile=app/javascript/src/graphql/__generated__/globalTypes.ts'
22 | )
23 | end
24 |
25 | desc 'Run all steps to generate typescript definitions'
26 | task gen: %w[clean schema:dump types]
27 | end
28 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/__generated__/SignOutUser.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL mutation operation: SignOutUser
7 | // ====================================================
8 |
9 | export interface SignOutUser_signOutUser_errors {
10 | __typename: "FormError";
11 | /**
12 | * Which field this error came from
13 | */
14 | path: string | null;
15 | /**
16 | * A description of the error
17 | */
18 | message: string;
19 | }
20 |
21 | export interface SignOutUser_signOutUser {
22 | __typename: "SignOutUserPayload";
23 | errors: SignOutUser_signOutUser_errors[];
24 | success: boolean;
25 | }
26 |
27 | export interface SignOutUser {
28 | signOutUser: SignOutUser_signOutUser | null;
29 | }
30 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/CreatePublicTaskMessage.ts:
--------------------------------------------------------------------------------
1 | /* Again, using separate mutations to be safe and make it
2 | * hard to mixup private and public */
3 | import {createMutationHook, gql} from '../graphqlHelpers';
4 | import {
5 | CreatePublicTaskMessage,
6 | CreatePublicTaskMessageVariables,
7 | } from './__generated__/CreatePublicTaskMessage';
8 |
9 | const createPublicTaskMessage = createMutationHook<
10 | CreatePublicTaskMessage,
11 | CreatePublicTaskMessageVariables
12 | >(gql`
13 | mutation CreatePublicTaskMessage($taskId: ID!, $message: String!) {
14 | createTaskMessages(taskId: $taskId, message: $message, isPublic: true) {
15 | success
16 | message {
17 | id
18 | message
19 | createdAt
20 | user {
21 | fullName
22 | }
23 | }
24 | }
25 | }
26 | `);
27 |
28 | export default createPublicTaskMessage;
29 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/list/CreateListPage/components/SelectTemplateStep/components/MAPane.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import clsx from 'clsx';
3 | import {Theme, makeStyles, createStyles} from '@material-ui/core/styles';
4 | import {Paper} from '@material-ui/core';
5 |
6 | const useStyles = makeStyles((theme: Theme) =>
7 | createStyles({
8 | root: {},
9 | invisible: {
10 | display: 'none',
11 | },
12 | })
13 | );
14 |
15 | interface MAPaneProps {
16 | value?: number;
17 | index?: number;
18 | }
19 |
20 | export default function MAPane(props: MAPaneProps) {
21 | const {value, index} = props;
22 | const classes = useStyles();
23 |
24 | return (
25 |
30 | M&A
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/graphqlHelpers.ts:
--------------------------------------------------------------------------------
1 | import {gql, ApolloError} from 'apollo-boost';
2 | import {useQuery, useMutation} from 'react-apollo';
3 | import {DocumentNode} from 'graphql';
4 | import {QueryResult, MutationTuple} from 'react-apollo';
5 |
6 | export {gql, useQuery};
7 |
8 | export function createQueryHook(
9 | query: DocumentNode
10 | ): (variables: TVariables) => QueryResult {
11 | return function(variables) {
12 | return useQuery(query, {variables});
13 | };
14 | }
15 |
16 | export function createMutationHook(
17 | mutation: DocumentNode
18 | ): (
19 | variables: TVariables,
20 | onCompleted?: (data: TData) => void,
21 | onError?: (error: ApolloError) => void
22 | ) => MutationTuple {
23 | return function(variables) {
24 | return useMutation(mutation, {
25 | variables,
26 | });
27 | };
28 | }
29 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/list/CreateListPage/components/SelectTemplateStep/components/LegalPane.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import clsx from 'clsx';
3 | import {Theme, makeStyles, createStyles} from '@material-ui/core/styles';
4 | import {Paper} from '@material-ui/core';
5 |
6 | const useStyles = makeStyles((theme: Theme) =>
7 | createStyles({
8 | root: {},
9 | invisible: {
10 | display: 'none',
11 | },
12 | })
13 | );
14 |
15 | interface LegalPaneProps {
16 | value?: number;
17 | index?: number;
18 | }
19 |
20 | export default function LegalPane(props: LegalPaneProps) {
21 | const {value, index} = props;
22 | const classes = useStyles();
23 |
24 | return (
25 |
30 | Legal
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/app/graphql/types/user_type.rb:
--------------------------------------------------------------------------------
1 | module Types
2 | class UserType < GraphQL::Schema::Object
3 | description 'User'
4 |
5 | field :id, ID, null: false
6 | field :fullName, String, null: false
7 | field :email, String, null: false
8 | field :displayName, String, null: true
9 | field :ownedCompanies, [CompanyType], null: true
10 | field :companies, [CompanyType], null: true
11 | field :teams, [TeamType], null: true
12 | field :roles, [RolesUserType], null: true
13 | field :lastViewedCompanyId, ID, null: true
14 | field :profile_url, String, null: true
15 |
16 | def profile_url
17 | if object.profile_picture.attached?
18 | Rails.application.routes.url_helpers.rails_blob_url(
19 | object.profile_picture,
20 | only_path: true
21 | )
22 | end
23 | end
24 |
25 | def roles
26 | object.roles_users
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/app/javascript/packs/application_pack.tsx:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | // This file is automatically compiled by Webpack, along with any other files
3 | // present in this directory. You're encouraged to place your actual application logic in
4 | // a relevant structure within app/javascript and only use these pack files to reference
5 | // that code so it'll be compiled.
6 | //
7 | // To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate
8 | // layout file, like app/views/layouts/application.html.erb
9 |
10 | // Uncomment to copy all static images under ../images to the output folder and reference
11 | // them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
12 | // or the `imagePath` JavaScript helper below.
13 | //
14 | // const images = require.context('../images', true)
15 | // const imagePath = (name) => images(name, true)
16 |
17 | import '../src/application';
18 |
--------------------------------------------------------------------------------
/spec/graphql/mutations/sign_up_user_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | module Mutations
4 | RSpec.describe SignUpUser, type: :request do
5 | describe 'resolve' do
6 | it 'Sign up user' do
7 | user = create(:user)
8 | expect do
9 | res =
10 | post '/graphql',
11 | params: {
12 | query: query(email: user.email, name: user.full_name)
13 | }
14 | to change { User.count }.by(1)
15 | end
16 | end
17 | end
18 |
19 | def query(email:, name:)
20 | <<~GQL
21 | mutation{
22 | signUpUser(
23 | email: #{email},
24 | fullName: #{
25 | name
26 | }
27 | ) {
28 | user {
29 | email
30 | }
31 | errors {
32 | path
33 | message
34 | }
35 | success
36 | }
37 | }
38 | GQL
39 | end
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/list/CreateListPage/components/SelectTemplateStep/components/FinancePane.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import clsx from 'clsx';
3 | import {Theme, makeStyles, createStyles} from '@material-ui/core/styles';
4 | import {Paper} from '@material-ui/core';
5 |
6 | const useStyles = makeStyles((theme: Theme) =>
7 | createStyles({
8 | root: {},
9 | invisible: {
10 | display: 'none',
11 | },
12 | })
13 | );
14 |
15 | interface FinancePaneProps {
16 | value?: number;
17 | index?: number;
18 | }
19 |
20 | export default function FinancePane(props: FinancePaneProps) {
21 | const {value, index} = props;
22 | const classes = useStyles();
23 |
24 | return (
25 |
30 | Finance
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/app/graphql/mutations/send_reset_password_instructions.rb:
--------------------------------------------------------------------------------
1 | class Mutations::SendResetPasswordInstructions < GraphQL::Schema::Mutation
2 | argument :email, String, required: true
3 |
4 | field :errors, [Types::FormErrorType], null: false
5 | field :success, Boolean, null: false
6 |
7 | def resolve(email: nil)
8 | response = { errors: [] }
9 |
10 | if context[:controller].user_signed_in?
11 | response[:errors].push({ path: 'root', message: 'Already signed in.' })
12 | response[:success] = false
13 | return response
14 | end
15 |
16 | user = User.find_for_database_authentication(email: email)
17 |
18 | unless user
19 | response[:errors].push({ path: 'email', message: 'Unrecognized email.' })
20 | response[:success] = false
21 | return response
22 | end
23 |
24 | user.send_reset_password_instructions
25 |
26 | response[:success] = true
27 | response
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/bin/update:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'fileutils'
3 | include FileUtils
4 |
5 | # path to your application root.
6 | APP_ROOT = File.expand_path('..', __dir__)
7 |
8 | def system!(*args)
9 | system(*args) || abort("\n== Command #{args} failed ==")
10 | end
11 |
12 | chdir APP_ROOT do
13 | # This script is a way to update your development environment automatically.
14 | # Add necessary update steps to this file.
15 |
16 | puts '== Installing dependencies =='
17 | system! 'gem install bundler --conservative'
18 | system('bundle check') || system!('bundle install')
19 |
20 | # Install JavaScript dependencies if using Yarn
21 | # system('bin/yarn')
22 |
23 | puts "\n== Updating database =="
24 | system! 'bin/rails db:migrate'
25 |
26 | puts "\n== Removing old logs and tempfiles =="
27 | system! 'bin/rails log:clear tmp:clear'
28 |
29 | puts "\n== Restarting application server =="
30 | system! 'bin/rails restart'
31 | end
32 |
--------------------------------------------------------------------------------
/app/assets/images/dummy/logos/drag.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/assets/images/dummy/logos/drag-black.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/SignInUser.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {SignInUser, SignInUserVariables} from './__generated__/SignInUser';
3 |
4 | export const useSignInUser = createMutationHook<
5 | SignInUser,
6 | SignInUserVariables
7 | >(gql`
8 | mutation SignInUser(
9 | $email: String!
10 | $password: String!
11 | $socialLogin: Boolean!
12 | $provider: String!
13 | $tokenID: String!
14 | $uuID: String!
15 | ) {
16 | signInUser(
17 | email: $email
18 | password: $password
19 | socialLogin: $socialLogin
20 | provider: $provider
21 | tokenID: $tokenID
22 | uuID: $uuID
23 | ) {
24 | currentUser {
25 | id
26 | user {
27 | id
28 | fullName
29 | email
30 | }
31 | }
32 | errors {
33 | path
34 | message
35 | }
36 | success
37 | }
38 | }
39 | `);
40 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/InviteNewCompanyToList.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {
3 | InviteNewCompanyToList,
4 | InviteNewCompanyToListVariables,
5 | } from './__generated__/InviteNewCompanyToList';
6 |
7 | export const useInviteNewCompanyToList = createMutationHook<
8 | InviteNewCompanyToList,
9 | InviteNewCompanyToListVariables
10 | >(gql`
11 | mutation InviteNewCompanyToList(
12 | $listId: ID!
13 | $companyId: ID!
14 | $ownerEmail: String!
15 | $newCompanyName: String!
16 | $isRequest: Boolean
17 | $isShare: Boolean
18 | ) {
19 | inviteNewCompanyToList(
20 | listId: $listId
21 | companyId: $companyId
22 | ownerEmail: $ownerEmail
23 | newCompanyName: $newCompanyName
24 | isRequest: $isRequest
25 | isShare: $isShare
26 | ) {
27 | errors {
28 | path
29 | message
30 | }
31 | success
32 | }
33 | }
34 | `);
35 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/queries/CurrentUser.ts:
--------------------------------------------------------------------------------
1 | import {createQueryHook, gql} from '../graphqlHelpers';
2 | import {
3 | CurrentUser,
4 | CurrentUser_currentUser_user,
5 | } from './__generated__/CurrentUser';
6 |
7 | export type User = CurrentUser_currentUser_user;
8 |
9 | export const useCurrentUser = createQueryHook(gql`
10 | query CurrentUser {
11 | currentUser {
12 | id
13 | user {
14 | id
15 | email
16 | fullName
17 | displayName
18 | profileUrl
19 | lastViewedCompanyId
20 | ownedCompanies {
21 | id
22 | name
23 | }
24 | companies {
25 | id
26 | name
27 | logoUrl
28 | }
29 | teams {
30 | id
31 | companyId
32 | name
33 | }
34 | roles {
35 | id
36 | name
37 | companyId
38 | }
39 | }
40 | }
41 | }
42 | `);
43 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/queries/__generated__/publicTaskMessages.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL query operation: publicTaskMessages
7 | // ====================================================
8 |
9 | export interface publicTaskMessages_publicTaskMessages_user {
10 | __typename: "User";
11 | fullName: string;
12 | }
13 |
14 | export interface publicTaskMessages_publicTaskMessages {
15 | __typename: "TaskMessage";
16 | message: string;
17 | user: publicTaskMessages_publicTaskMessages_user;
18 | createdAt: string;
19 | }
20 |
21 | export interface publicTaskMessages {
22 | /**
23 | * A separate query to retrieve public messages
24 | */
25 | publicTaskMessages: publicTaskMessages_publicTaskMessages[];
26 | }
27 |
28 | export interface publicTaskMessagesVariables {
29 | taskId: string;
30 | }
31 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/RemoveTeamMember.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {
3 | RemoveTeamMember,
4 | RemoveTeamMemberVariables,
5 | } from './__generated__/RemoveTeamMember';
6 |
7 | export const useRemoveTeamMember = createMutationHook<
8 | RemoveTeamMember,
9 | RemoveTeamMemberVariables
10 | >(gql`
11 | mutation RemoveTeamMember($teamId: ID!, $userId: ID!, $userIds: [ID!]) {
12 | removeTeamMember(teamId: $teamId, userId: $userId, userIds: $userIds) {
13 | user {
14 | id
15 | fullName
16 | profileUrl
17 | roles {
18 | id
19 | name
20 | companyId
21 | }
22 | teams {
23 | id
24 | name
25 | companyId
26 | }
27 | companies {
28 | id
29 | name
30 | }
31 | }
32 | errors {
33 | path
34 | message
35 | }
36 | success
37 | }
38 | }
39 | `);
40 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/queries/__generated__/UserLists.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL query operation: UserLists
7 | // ====================================================
8 |
9 | export interface UserLists_userLists_lists_sections {
10 | __typename: "TaskSection";
11 | id: string;
12 | name: string | null;
13 | }
14 |
15 | export interface UserLists_userLists_lists {
16 | __typename: "List";
17 | id: string;
18 | name: string | null;
19 | sections: UserLists_userLists_lists_sections[] | null;
20 | }
21 |
22 | export interface UserLists_userLists {
23 | __typename: "UserList";
24 | id: string;
25 | lists: UserLists_userLists_lists[] | null;
26 | }
27 |
28 | export interface UserLists {
29 | /**
30 | * All users lists & tasks in current company
31 | */
32 | userLists: UserLists_userLists;
33 | }
34 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/queries/__generated__/privateTaskMessages.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL query operation: privateTaskMessages
7 | // ====================================================
8 |
9 | export interface privateTaskMessages_privateTaskMessages_user {
10 | __typename: "User";
11 | fullName: string;
12 | }
13 |
14 | export interface privateTaskMessages_privateTaskMessages {
15 | __typename: "TaskMessage";
16 | message: string;
17 | user: privateTaskMessages_privateTaskMessages_user;
18 | createdAt: string;
19 | }
20 |
21 | export interface privateTaskMessages {
22 | /**
23 | * A separate query to retrieve private messages
24 | */
25 | privateTaskMessages: privateTaskMessages_privateTaskMessages[];
26 | }
27 |
28 | export interface privateTaskMessagesVariables {
29 | taskId: string;
30 | }
31 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Files in the config/locales directory are used for internationalization
2 | # and are automatically loaded by Rails. If you want to use locales other
3 | # than English, add the necessary files in this directory.
4 | #
5 | # To use the locales, use `I18n.t`:
6 | #
7 | # I18n.t 'hello'
8 | #
9 | # In views, this is aliased to just `t`:
10 | #
11 | # <%= t('hello') %>
12 | #
13 | # To use a different locale, set it with `I18n.locale`:
14 | #
15 | # I18n.locale = :es
16 | #
17 | # This would use the information in config/locales/es.yml.
18 | #
19 | # The following keys must be escaped otherwise they will not be retrieved by
20 | # the default I18n backend:
21 | #
22 | # true, false, on, off, yes, no
23 | #
24 | # Instead, surround them with single quotes.
25 | #
26 | # en:
27 | # 'true': 'foo'
28 | #
29 | # To learn more, please read the Rails Internationalization guide
30 | # available at http://guides.rubyonrails.org/i18n.html.
31 |
32 | en:
33 | hello: "Hello world"
34 |
--------------------------------------------------------------------------------
/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 Prepdd
10 | class Application < Rails::Application
11 | # Initialize configuration defaults for originally generated Rails version.
12 | config.load_defaults 5.2
13 |
14 | # Settings in config/environments/* take precedence over those specified here.
15 | # Application configuration can go into files in config/initializers
16 | # -- all .rb files in that directory are automatically loaded after loading
17 | # the framework and any gems in your application.
18 | # config.generators.javascript_engine = :js
19 | config.generators.stylesheets = false
20 | config.generators.javascripts = false
21 | config.generators.helper = false
22 |
23 | config.autoload_paths << Rails.root.join('graphql', 'types')
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/CreateAssociatedCompany.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {
3 | CreateAssociatedCompany,
4 | CreateAssociatedCompanyVariables,
5 | } from './__generated__/CreateAssociatedCompany';
6 |
7 | export const useCreateAssociatedCompany = createMutationHook<
8 | CreateAssociatedCompany,
9 | CreateAssociatedCompanyVariables
10 | >(gql`
11 | mutation CreateAssociatedCompany(
12 | $companyId: ID!
13 | $ownerEmail: String!
14 | $newCompanyName: String!
15 | $isParent: Boolean
16 | $isBroker: Boolean
17 | ) {
18 | createAssociatedCompany(
19 | companyId: $companyId
20 | ownerEmail: $ownerEmail
21 | newCompanyName: $newCompanyName
22 | isParent: $isParent
23 | isBroker: $isBroker
24 | ) {
25 | company {
26 | id
27 | name
28 | logoUrl
29 | }
30 | errors {
31 | path
32 | message
33 | }
34 | success
35 | }
36 | }
37 | `);
38 |
--------------------------------------------------------------------------------
/.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 |
10 | # Ignore the default SQLite database.
11 | /db/*.sqlite3
12 | /db/*.sqlite3-journal
13 |
14 | .idea/
15 |
16 | # Ignore all logfiles and tempfiles.
17 | /log/*
18 | /tmp/*
19 | !/log/.keep
20 | !/tmp/.keep
21 |
22 | # Ignore uploaded files in development
23 | /storage/*
24 | !/storage/.keep
25 |
26 | /node_modules
27 | /yarn-error.log
28 |
29 | /public/assets
30 | .byebug_history
31 |
32 | # Ignore master key for decrypting credentials and more.
33 | /config/master.key
34 |
35 | /public/packs
36 | /public/packs-test
37 | /node_modules
38 | /yarn-error.log
39 | yarn-debug.log*
40 | .yarn-integrity
41 |
42 | .DS_Store
43 | coverage
44 |
45 | /.env
--------------------------------------------------------------------------------
/app/javascript/src/graphql/queries/CompanyUsers.ts:
--------------------------------------------------------------------------------
1 | import {createQueryHook, gql} from '../graphqlHelpers';
2 | import {CompanyUsers} from './__generated__/CompanyUsers';
3 |
4 | export const useCompanyUsers = createQueryHook(gql`
5 | query CompanyUsers($companyId: ID!, $teamId: ID, $limit: Int, $offset: Int) {
6 | companyUsers(
7 | CompanyId: $companyId
8 | TeamId: $teamId
9 | limit: $limit
10 | offset: $offset
11 | ) {
12 | company {
13 | id
14 | name
15 | teams {
16 | id
17 | name
18 | }
19 | }
20 | users {
21 | id
22 | fullName
23 | profileUrl
24 | roles {
25 | id
26 | name
27 | companyId
28 | }
29 | teams {
30 | id
31 | name
32 | companyId
33 | }
34 | companies {
35 | id
36 | name
37 | logoUrl
38 | }
39 | }
40 | }
41 | }
42 | `);
43 |
--------------------------------------------------------------------------------
/app/workers/company/remove_un_used_companies_worker.rb:
--------------------------------------------------------------------------------
1 | class Company::RemoveUnUsedCompaniesWorker
2 | include Sidekiq::Worker
3 |
4 | def perform
5 | Company.where(owner_id: nil).each do |company|
6 | if company.created_at < 1.day.ago
7 | begin
8 | # Remove s3 bucket of company
9 | if company.s3_location?
10 | s3_client = Aws::S3::Client.new
11 | bucket_name = company.s3_location.gsub('/', '')
12 | s3_client.delete_bucket(bucket: bucket_name)
13 | end
14 |
15 | # Remove KMS key of company
16 | if company.kms_key_id?
17 | client = Aws::KMS::Client.new
18 | key_id = company.kms_key_id
19 | resp =
20 | client.schedule_key_deletion(
21 | { key_id: key_id, pending_window_in_days: 7 }
22 | )
23 | end
24 | rescue StandardError
25 |
26 | end
27 |
28 | company.destroy
29 | end
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/__generated__/CreateTask.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | import { TaskAttributes } from "./../../__generated__/globalTypes";
6 |
7 | // ====================================================
8 | // GraphQL mutation operation: CreateTask
9 | // ====================================================
10 |
11 | export interface CreateTask_createTask_errors {
12 | __typename: "FormError";
13 | /**
14 | * Which field this error came from
15 | */
16 | path: string | null;
17 | /**
18 | * A description of the error
19 | */
20 | message: string;
21 | }
22 |
23 | export interface CreateTask_createTask {
24 | __typename: "CreateTaskPayload";
25 | errors: CreateTask_createTask_errors[];
26 | success: boolean;
27 | }
28 |
29 | export interface CreateTask {
30 | createTask: CreateTask_createTask | null;
31 | }
32 |
33 | export interface CreateTaskVariables {
34 | listId: string;
35 | tasks: TaskAttributes[];
36 | }
37 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/RemoveCompanyMember.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {
3 | RemoveCompanyMember,
4 | RemoveCompanyMemberVariables,
5 | } from './__generated__/RemoveCompanyMember';
6 |
7 | export const useRemoveCompanyMember = createMutationHook<
8 | RemoveCompanyMember,
9 | RemoveCompanyMemberVariables
10 | >(gql`
11 | mutation RemoveCompanyMember($companyId: ID!, $userId: ID, $userIds: [ID!]) {
12 | removeCompanyMember(
13 | companyId: $companyId
14 | userId: $userId
15 | userIds: $userIds
16 | ) {
17 | errors {
18 | path
19 | message
20 | }
21 | success
22 | user {
23 | id
24 | fullName
25 | profileUrl
26 | roles {
27 | id
28 | name
29 | companyId
30 | }
31 | teams {
32 | id
33 | name
34 | companyId
35 | }
36 | companies {
37 | id
38 | name
39 | }
40 | }
41 | }
42 | }
43 | `);
44 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/__generated__/AddListOwner.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL mutation operation: AddListOwner
7 | // ====================================================
8 |
9 | export interface AddListOwner_addListOwner_errors {
10 | __typename: "FormError";
11 | /**
12 | * Which field this error came from
13 | */
14 | path: string | null;
15 | /**
16 | * A description of the error
17 | */
18 | message: string;
19 | }
20 |
21 | export interface AddListOwner_addListOwner {
22 | __typename: "AddListOwnerPayload";
23 | errors: AddListOwner_addListOwner_errors[];
24 | success: boolean;
25 | }
26 |
27 | export interface AddListOwner {
28 | addListOwner: AddListOwner_addListOwner | null;
29 | }
30 |
31 | export interface AddListOwnerVariables {
32 | listId: string;
33 | companyId: string;
34 | userEmails?: string[] | null;
35 | teamIds?: string[] | null;
36 | }
37 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/queries/UserTasks.ts:
--------------------------------------------------------------------------------
1 | import {createQueryHook, gql} from '../graphqlHelpers';
2 | import {UserTasks} from './__generated__/UserTasks';
3 |
4 | export const useUserTasks = createQueryHook(gql`
5 | query UserTasks(
6 | $listIds: [ID!]!
7 | $sectionIds: [ID!]!
8 | $offset: Int
9 | $limit: Int
10 | ) {
11 | userTasks(
12 | listIds: $listIds
13 | sectionIds: $sectionIds
14 | offset: $offset
15 | limit: $limit
16 | ) {
17 | id
18 | name
19 | priority
20 | status
21 | dueDate
22 | updatedAt
23 | listNumber
24 | list {
25 | id
26 | }
27 | userOwners {
28 | id
29 | email
30 | fullName
31 | profileUrl
32 | }
33 | teamOwners {
34 | id
35 | name
36 | }
37 | userReviewers {
38 | id
39 | email
40 | fullName
41 | profileUrl
42 | }
43 | teamReviewers {
44 | id
45 | name
46 | }
47 | }
48 | }
49 | `);
50 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/__generated__/UpdateUserPassword.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL mutation operation: UpdateUserPassword
7 | // ====================================================
8 |
9 | export interface UpdateUserPassword_updateUserPassword_errors {
10 | __typename: "FormError";
11 | /**
12 | * Which field this error came from
13 | */
14 | path: string | null;
15 | /**
16 | * A description of the error
17 | */
18 | message: string;
19 | }
20 |
21 | export interface UpdateUserPassword_updateUserPassword {
22 | __typename: "UpdateUserPasswordPayload";
23 | errors: UpdateUserPassword_updateUserPassword_errors[];
24 | success: boolean;
25 | }
26 |
27 | export interface UpdateUserPassword {
28 | updateUserPassword: UpdateUserPassword_updateUserPassword | null;
29 | }
30 |
31 | export interface UpdateUserPasswordVariables {
32 | password: string;
33 | oldPassword: string;
34 | }
35 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/__generated__/UpdateUserData.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL mutation operation: UpdateUserData
7 | // ====================================================
8 |
9 | export interface UpdateUserData_updateUserData_errors {
10 | __typename: "FormError";
11 | /**
12 | * Which field this error came from
13 | */
14 | path: string | null;
15 | /**
16 | * A description of the error
17 | */
18 | message: string;
19 | }
20 |
21 | export interface UpdateUserData_updateUserData {
22 | __typename: "UpdateUserDataPayload";
23 | errors: UpdateUserData_updateUserData_errors[];
24 | success: boolean;
25 | }
26 |
27 | export interface UpdateUserData {
28 | updateUserData: UpdateUserData_updateUserData | null;
29 | }
30 |
31 | export interface UpdateUserDataVariables {
32 | email: string;
33 | fullName: string;
34 | displayName: string;
35 | lastViewedCompanyId?: string | null;
36 | }
37 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/list/CreateListPage/components/CreateListStep/components/Alert.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Theme, makeStyles, createStyles} from '@material-ui/core/styles';
3 | import Typography from '@material-ui/core/Typography';
4 | import WarningIcon from '@material-ui/icons/WarningRounded';
5 |
6 | const useStyles = makeStyles((theme: Theme) =>
7 | createStyles({
8 | root: {
9 | display: 'flex',
10 | width: '100%',
11 | alignItems: 'center',
12 | backgroundColor: 'rgba(248,231,28,0.20)',
13 | border: '1px solid #D8D8D8',
14 | borderRadius: '3px',
15 | marginTop: '12px',
16 | padding: '12px 20px',
17 | },
18 | })
19 | );
20 |
21 | export default function Alert() {
22 | const classes = useStyles();
23 |
24 | return (
25 |
26 |
27 |
28 | This list and all of it’s contents will be public to the selected
29 | company upon creation.
30 |
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/route/app.tsx:
--------------------------------------------------------------------------------
1 | import LoadingFallback from '../common/LoadingFallback';
2 | import React, {lazy, Suspense} from 'react';
3 | import {Switch, Route} from 'react-router-dom';
4 |
5 | const Layout = lazy(() => import('../layout'));
6 | const CompanyRoutes = lazy(() => import('./company'));
7 | const TeamRoutes = lazy(() => import('./team'));
8 | const UserRoutes = lazy(() => import('./user'));
9 | const ListRoutes = lazy(() => import('./list'));
10 | const TaskRoutes = lazy(() => import('./task'));
11 |
12 | export default function AppRoute() {
13 | return (
14 | }>
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'fileutils'
3 | include FileUtils
4 |
5 | # path to your application root.
6 | APP_ROOT = File.expand_path('..', __dir__)
7 |
8 | def system!(*args)
9 | system(*args) || abort("\n== Command #{args} failed ==")
10 | end
11 |
12 | chdir APP_ROOT do
13 | # This script is a starting point to setup your application.
14 | # Add necessary setup steps to this file.
15 |
16 | puts '== Installing dependencies =='
17 | system! 'gem install bundler --conservative'
18 | system('bundle check') || system!('bundle install')
19 |
20 | # Install JavaScript dependencies if using Yarn
21 | # system('bin/yarn')
22 |
23 | # puts "\n== Copying sample files =="
24 | # unless File.exist?('config/database.yml')
25 | # cp 'config/database.yml.sample', 'config/database.yml'
26 | # end
27 |
28 | puts "\n== Preparing database =="
29 | system! 'bin/rails db:setup'
30 |
31 | puts "\n== Removing old logs and tempfiles =="
32 | system! 'bin/rails log:clear tmp:clear'
33 |
34 | puts "\n== Restarting application server =="
35 | system! 'bin/rails restart'
36 | end
37 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/UpdateTeamMember.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {
3 | UpdateTeamMember,
4 | UpdateTeamMemberVariables,
5 | } from './__generated__/UpdateTeamMember';
6 |
7 | export const useUpdateTeamMember = createMutationHook<
8 | UpdateTeamMember,
9 | UpdateTeamMemberVariables
10 | >(gql`
11 | mutation UpdateTeamMember(
12 | $id: ID!
13 | $fullName: String!
14 | $companyId: ID!
15 | $role: ID!
16 | ) {
17 | updateTeamMember(
18 | id: $id
19 | fullName: $fullName
20 | companyId: $companyId
21 | role: $role
22 | ) {
23 | success
24 | errors {
25 | path
26 | message
27 | }
28 | user {
29 | id
30 | fullName
31 | profileUrl
32 | roles {
33 | id
34 | name
35 | companyId
36 | }
37 | teams {
38 | id
39 | name
40 | companyId
41 | }
42 | companies {
43 | id
44 | name
45 | logoUrl
46 | }
47 | }
48 | }
49 | }
50 | `);
51 |
--------------------------------------------------------------------------------
/app/graphql/types/list_type.rb:
--------------------------------------------------------------------------------
1 | module Types
2 | class ListType < GraphQL::Schema::Object
3 | description 'Lists'
4 |
5 | field :id, String, null: false
6 | field :name, String, null: true
7 | field :description, String, null: true
8 | field :isActive, Boolean, null: true
9 | field :isTemplate, Boolean, null: true
10 | field :isPublicTemplate, Boolean, null: true
11 | field :requesterCompany, CompanyType, null: true
12 | field :responderCompany, CompanyType, null: true
13 | field :tasks, [TaskType], null: true
14 | field :owners, [UserType], null: true
15 | field :sections, [TaskSectionType], null: true
16 | field :requester_rank, Integer, null: true
17 | field :responder_rank, Integer, null: true
18 |
19 | def requester_company
20 | object.requester
21 | end
22 |
23 | def responder_company
24 | object.responder
25 | end
26 |
27 | def sections
28 | sections =
29 | object.tasks.includes(:task_section).map do |task|
30 | task.task_section&.id
31 | end
32 | TaskSection.where(id: sections)
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/db/migrate/20190822034212_create_active_storage_tables.active_storage.rb:
--------------------------------------------------------------------------------
1 | # This migration comes from active_storage (originally 20170806125915)
2 | class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
3 | def change
4 | create_table :active_storage_blobs do |t|
5 | t.string :key, null: false
6 | t.string :filename, null: false
7 | t.string :content_type
8 | t.text :metadata
9 | t.bigint :byte_size, null: false
10 | t.string :checksum, null: false
11 | t.datetime :created_at, null: false
12 |
13 | t.index [ :key ], unique: true
14 | end
15 |
16 | create_table :active_storage_attachments do |t|
17 | t.string :name, null: false
18 | t.references :record, null: false, polymorphic: true, index: false
19 | t.references :blob, null: false
20 |
21 | t.datetime :created_at, null: false
22 |
23 | t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
24 | t.foreign_key :active_storage_blobs, column: :blob_id
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/queries/__generated__/AllTemplates.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL query operation: AllTemplates
7 | // ====================================================
8 |
9 | export interface AllTemplates_templateLists_tasks_section {
10 | __typename: "TaskSection";
11 | id: string;
12 | name: string | null;
13 | }
14 |
15 | export interface AllTemplates_templateLists_tasks {
16 | __typename: "Task";
17 | id: string;
18 | name: string | null;
19 | section: AllTemplates_templateLists_tasks_section | null;
20 | description: string | null;
21 | priority: string | null;
22 | status: string | null;
23 | }
24 |
25 | export interface AllTemplates_templateLists {
26 | __typename: "List";
27 | id: string;
28 | name: string | null;
29 | tasks: AllTemplates_templateLists_tasks[] | null;
30 | }
31 |
32 | export interface AllTemplates {
33 | /**
34 | * All Available lists templates
35 | */
36 | templateLists: AllTemplates_templateLists[];
37 | }
38 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/AddTeamMember.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {
3 | AddTeamMember,
4 | AddTeamMemberVariables,
5 | } from './__generated__/AddTeamMember';
6 |
7 | export const useAddTeamMember = createMutationHook<
8 | AddTeamMember,
9 | AddTeamMemberVariables
10 | >(gql`
11 | mutation AddTeamMember(
12 | $email: String!
13 | $fullName: String!
14 | $role: ID!
15 | $team: String!
16 | $companyId: ID!
17 | ) {
18 | addTeamMember(
19 | email: $email
20 | fullName: $fullName
21 | role: $role
22 | team: $team
23 | companyId: $companyId
24 | ) {
25 | errors {
26 | path
27 | message
28 | }
29 | success
30 | user {
31 | id
32 | fullName
33 | profileUrl
34 | roles {
35 | id
36 | name
37 | companyId
38 | }
39 | teams {
40 | id
41 | name
42 | companyId
43 | }
44 | companies {
45 | id
46 | name
47 | logoUrl
48 | }
49 | }
50 | }
51 | }
52 | `);
53 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/__generated__/CreateCompany.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL mutation operation: CreateCompany
7 | // ====================================================
8 |
9 | export interface CreateCompany_createCompany_company {
10 | __typename: "Company";
11 | name: string;
12 | }
13 |
14 | export interface CreateCompany_createCompany_errors {
15 | __typename: "FormError";
16 | /**
17 | * Which field this error came from
18 | */
19 | path: string | null;
20 | /**
21 | * A description of the error
22 | */
23 | message: string;
24 | }
25 |
26 | export interface CreateCompany_createCompany {
27 | __typename: "CreateCompanyPayload";
28 | company: CreateCompany_createCompany_company | null;
29 | errors: CreateCompany_createCompany_errors[];
30 | success: boolean;
31 | }
32 |
33 | export interface CreateCompany {
34 | createCompany: CreateCompany_createCompany | null;
35 | }
36 |
37 | export interface CreateCompanyVariables {
38 | name: string;
39 | }
40 |
--------------------------------------------------------------------------------
/app/graphql/mutations/create_team.rb:
--------------------------------------------------------------------------------
1 | class Mutations::CreateTeam < GraphQL::Schema::Mutation
2 | argument :name, String, required: true
3 | argument :companyID, String, required: true
4 |
5 | field :team, Types::TeamType, null: true
6 | field :errors, [Types::FormErrorType], null: false
7 | field :success, Boolean, null: false
8 |
9 | def resolve(name: nil, company_id: nil)
10 | response = { errors: [] }
11 |
12 | if !context[:controller].user_signed_in?
13 | response[:errors].push(
14 | { path: 'root', message: 'Not authorized to do it.' }
15 | )
16 | response[:success] = false
17 | return response
18 | end
19 |
20 | team = Team.create(name: name, company_id: company_id, is_active: true)
21 |
22 | team.errors.messages.each do |path, messages|
23 | messages.each do |message|
24 | response[:errors].push(
25 | { path: path.to_s.camelcase(:lower), message: message }
26 | )
27 | response[:success] = false
28 | end
29 | end
30 |
31 | if team&.persisted?
32 | response[:success] = true
33 | response
34 | end
35 |
36 | response
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/file/FilesPage/components/Body/Body.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import clsx from 'clsx';
3 | import idx from 'idx';
4 | import {Theme, makeStyles, createStyles} from '@material-ui/core/styles';
5 | import {Typography} from '@material-ui/core';
6 |
7 | import Panel from '../../../../common/Panel';
8 | import SingleTask from './components/SingleTask';
9 | import MultipleTasks from './components/MultipleTasks';
10 |
11 | const useStyles = makeStyles((theme: Theme) =>
12 | createStyles({
13 | root: {
14 | padding: '0px calc((100% - 1080px) / 2) 0px calc((100% - 1080px) / 2)',
15 | },
16 | flex: {
17 | display: 'flex',
18 | alignItems: 'center',
19 | },
20 | })
21 | );
22 |
23 | const labels = [
24 | { label: 'Single Task' },
25 | { label: 'Multiple Tasks' },
26 | ];
27 |
28 | export default function Body() {
29 | const classes = useStyles();
30 |
31 | return (
32 |
33 |
Add Files
34 |
35 |
36 |
37 |
38 |
39 | );
40 | }
41 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/__generated__/SendPasswordResetInstructions.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL mutation operation: SendPasswordResetInstructions
7 | // ====================================================
8 |
9 | export interface SendPasswordResetInstructions_sendResetPasswordInstructions_errors {
10 | __typename: "FormError";
11 | /**
12 | * Which field this error came from
13 | */
14 | path: string | null;
15 | /**
16 | * A description of the error
17 | */
18 | message: string;
19 | }
20 |
21 | export interface SendPasswordResetInstructions_sendResetPasswordInstructions {
22 | __typename: "SendResetPasswordInstructionsPayload";
23 | errors: SendPasswordResetInstructions_sendResetPasswordInstructions_errors[];
24 | success: boolean;
25 | }
26 |
27 | export interface SendPasswordResetInstructions {
28 | sendResetPasswordInstructions: SendPasswordResetInstructions_sendResetPasswordInstructions | null;
29 | }
30 |
31 | export interface SendPasswordResetInstructionsVariables {
32 | email: string;
33 | }
34 |
--------------------------------------------------------------------------------
/spec/graphql/types/team_type_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 | module Types
3 | RSpec.describe TeamType do
4 | set_graphql_type
5 | # avail type definer in our tests
6 | types = GraphQL::Define::TypeDefiner.instance
7 |
8 | it 'has an :id field of ID type' do
9 | # Ensure that the field id is of type ID
10 | expect(subject.fields['id'].type.to_type_signature).to eq('ID!')
11 | end
12 |
13 | it 'has an :companyId field of ID type' do
14 | # Ensure that the field id is of type ID
15 | expect(subject.fields['companyId'].type.to_type_signature).to eq('ID!')
16 | end
17 |
18 | it 'has a :name field of String type' do
19 | # Ensure the field is of String type
20 | expect(subject.fields['name'].type.to_type_signature).to eq('String!')
21 | end
22 |
23 | it 'has :users field of User type' do
24 | # Ensure the field is of User type
25 | expect(subject.fields['users'].type.to_type_signature).to eq('[User!]!')
26 | end
27 |
28 | it 'has :company field of Company type' do
29 | # Ensure the field is of Company type
30 | expect(subject.fields['company'].type.to_type_signature).to eq('Company!')
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/app/javascript/src/helpers/__generated__/SearchCompanyUsers.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL query operation: SearchCompanyUsers
7 | // ====================================================
8 |
9 | export interface SearchCompanyUsers_searchCompanyUsers_users {
10 | __typename: "User";
11 | id: string;
12 | email: string;
13 | fullName: string;
14 | profileUrl: string | null;
15 | }
16 |
17 | export interface SearchCompanyUsers_searchCompanyUsers_teams {
18 | __typename: "Team";
19 | id: string;
20 | name: string;
21 | }
22 |
23 | export interface SearchCompanyUsers_searchCompanyUsers {
24 | __typename: "SearchCompanyUsers";
25 | users: SearchCompanyUsers_searchCompanyUsers_users[] | null;
26 | teams: SearchCompanyUsers_searchCompanyUsers_teams[] | null;
27 | }
28 |
29 | export interface SearchCompanyUsers {
30 | /**
31 | * Search users by company id
32 | */
33 | searchCompanyUsers: SearchCompanyUsers_searchCompanyUsers;
34 | }
35 |
36 | export interface SearchCompanyUsersVariables {
37 | text: string;
38 | companyId: string;
39 | }
40 |
--------------------------------------------------------------------------------
/config/initializers/content_security_policy.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Define an application-wide content security policy
4 | # For further information see the following documentation
5 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
6 |
7 | # Rails.application.config.content_security_policy do |policy|
8 | # policy.default_src :self, :https
9 | # policy.font_src :self, :https, :data
10 | # policy.img_src :self, :https, :data
11 | # policy.object_src :none
12 | # policy.script_src :self, :https
13 | # policy.style_src :self, :https
14 |
15 | # # Specify URI for violation reports
16 | # # policy.report_uri "/csp-violation-report-endpoint"
17 | # end
18 |
19 | # If you are using UJS then enable automatic nonce generation
20 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
21 |
22 | # Report CSP violations to a specified URI
23 | # For further information see the following documentation:
24 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
25 | # Rails.application.config.content_security_policy_report_only = true
26 |
--------------------------------------------------------------------------------
/app/graphql/mutations/update_task.rb:
--------------------------------------------------------------------------------
1 | class Mutations::UpdateTask < GraphQL::Schema::Mutation
2 | argument :id, ID, required: true
3 | argument :name, String, required: false
4 | argument :description, String, required: false
5 | argument :priority, String, required: false
6 | argument :status, String, required: false
7 | argument :dueDate, String, required: false
8 |
9 | field :task, Types::TaskType, null: false
10 | field :errors, [Types::FormErrorType], null: false
11 | field :success, Boolean, null: false
12 |
13 | def resolve(
14 | id: nil,
15 | name: nil,
16 | description: nil,
17 | priority: nil,
18 | status: nil,
19 | due_date: nil
20 | )
21 | response = { errors: [] }
22 |
23 | task = Task.find(id)
24 |
25 | task.update(name: name) if name.present?
26 |
27 | task.update(description: description) if description.present?
28 |
29 | task.update(priority: priority) if priority.present?
30 |
31 | task.update(status: status) if status.present?
32 |
33 | task.update(due_date: due_date) if due_date.present?
34 |
35 | if task&.persisted?
36 | response[:success] = true
37 | response[:task] = task
38 | end
39 |
40 | response
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/__generated__/CreatePublicTaskMessage.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL mutation operation: CreatePublicTaskMessage
7 | // ====================================================
8 |
9 | export interface CreatePublicTaskMessage_createTaskMessages_message_user {
10 | __typename: "User";
11 | fullName: string;
12 | }
13 |
14 | export interface CreatePublicTaskMessage_createTaskMessages_message {
15 | __typename: "TaskMessage";
16 | id: string;
17 | message: string;
18 | createdAt: string;
19 | user: CreatePublicTaskMessage_createTaskMessages_message_user;
20 | }
21 |
22 | export interface CreatePublicTaskMessage_createTaskMessages {
23 | __typename: "CreateTaskMessagesPayload";
24 | success: boolean;
25 | message: CreatePublicTaskMessage_createTaskMessages_message | null;
26 | }
27 |
28 | export interface CreatePublicTaskMessage {
29 | createTaskMessages: CreatePublicTaskMessage_createTaskMessages | null;
30 | }
31 |
32 | export interface CreatePublicTaskMessageVariables {
33 | taskId: string;
34 | message: string;
35 | }
36 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/__generated__/CreatePrivateTaskMessage.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL mutation operation: CreatePrivateTaskMessage
7 | // ====================================================
8 |
9 | export interface CreatePrivateTaskMessage_createTaskMessages_message_user {
10 | __typename: "User";
11 | fullName: string;
12 | }
13 |
14 | export interface CreatePrivateTaskMessage_createTaskMessages_message {
15 | __typename: "TaskMessage";
16 | id: string;
17 | message: string;
18 | createdAt: string;
19 | user: CreatePrivateTaskMessage_createTaskMessages_message_user;
20 | }
21 |
22 | export interface CreatePrivateTaskMessage_createTaskMessages {
23 | __typename: "CreateTaskMessagesPayload";
24 | success: boolean;
25 | message: CreatePrivateTaskMessage_createTaskMessages_message | null;
26 | }
27 |
28 | export interface CreatePrivateTaskMessage {
29 | createTaskMessages: CreatePrivateTaskMessage_createTaskMessages | null;
30 | }
31 |
32 | export interface CreatePrivateTaskMessageVariables {
33 | taskId: string;
34 | message: string;
35 | }
36 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/__generated__/InviteNewCompanyToList.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL mutation operation: InviteNewCompanyToList
7 | // ====================================================
8 |
9 | export interface InviteNewCompanyToList_inviteNewCompanyToList_errors {
10 | __typename: "FormError";
11 | /**
12 | * Which field this error came from
13 | */
14 | path: string | null;
15 | /**
16 | * A description of the error
17 | */
18 | message: string;
19 | }
20 |
21 | export interface InviteNewCompanyToList_inviteNewCompanyToList {
22 | __typename: "InviteNewCompanyToListPayload";
23 | errors: InviteNewCompanyToList_inviteNewCompanyToList_errors[];
24 | success: boolean;
25 | }
26 |
27 | export interface InviteNewCompanyToList {
28 | inviteNewCompanyToList: InviteNewCompanyToList_inviteNewCompanyToList | null;
29 | }
30 |
31 | export interface InviteNewCompanyToListVariables {
32 | listId: string;
33 | companyId: string;
34 | ownerEmail: string;
35 | newCompanyName: string;
36 | isRequest?: boolean | null;
37 | isShare?: boolean | null;
38 | }
39 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/user/UserProfile.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import clsx from 'clsx';
3 | import {makeStyles} from '@material-ui/core/styles';
4 | import Typography from '@material-ui/core/Typography';
5 |
6 | import Panel from '../common/Panel';
7 | import ProfilePane from './components/ProfilePane';
8 | import NotificationPane from './components/NotificationPane';
9 |
10 | const useStyle = makeStyles({
11 | root: {
12 | display: 'block',
13 | padding: `84px calc((100% - 900px) / 2) 0px calc((100% - 900px) / 2)`,
14 | height: 'calc(100vh - 64px)',
15 | },
16 | title: {
17 | color: '#2C2C2C',
18 | fontFamily: 'Montserrat',
19 | fontSize: '24px',
20 | fontWeight: 'bold',
21 | },
22 | });
23 |
24 | const labels = [
25 | {label: 'Personal Information'},
26 | {label: 'Notification Settings'},
27 | ];
28 |
29 | export default function Profile(props: {path?: string}) {
30 | const classes = useStyle();
31 |
32 | return (
33 |
34 |
35 | Profile
36 |
37 |
38 |
39 |
40 |
41 |
42 | );
43 | }
44 |
--------------------------------------------------------------------------------
/app/graphql/mutations/update_user_data.rb:
--------------------------------------------------------------------------------
1 | class Mutations::UpdateUserData < GraphQL::Schema::Mutation
2 | argument :fullName, String, required: true
3 | argument :email, String, required: true
4 | argument :displayName, String, required: true
5 | argument :lastViewedCompanyId, ID, required: false
6 |
7 | field :user, Types::UserType, null: true
8 | field :errors, [Types::FormErrorType], null: false
9 | field :success, Boolean, null: false
10 |
11 | def resolve(
12 | full_name: nil, email: nil, display_name: nil, last_viewed_company_id: nil
13 | )
14 | response = { errors: [] }
15 |
16 | user = context[:controller].current_user
17 |
18 | user.update(
19 | {
20 | full_name: full_name,
21 | email: email,
22 | display_name: display_name,
23 | last_viewed_company_id: last_viewed_company_id
24 | }
25 | )
26 |
27 | user.errors.messages.each do |path, messages|
28 | messages.each do |message|
29 | response[:errors].push(
30 | { path: path.to_s.camelcase(:lower), message: message }
31 | )
32 | response[:success] = false
33 | end
34 | end
35 |
36 | if user.persisted?
37 | response[:success] = true
38 | response
39 | end
40 |
41 | response
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/user/components/NotificationPane/NotificationPane.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import clsx from 'clsx';
3 | import {Theme, makeStyles, createStyles} from '@material-ui/core/styles';
4 | import {Paper, Typography, Select, MenuItem} from '@material-ui/core';
5 |
6 | const useStyles = makeStyles((theme: Theme) =>
7 | createStyles({
8 | root: {
9 | paddingTop: '36px',
10 | },
11 | invisible: {
12 | display: 'none',
13 | },
14 | title: {
15 | fontFamily: 'Montserrat',
16 | fontSize: '24px',
17 | fontWeight: 'bold',
18 | color: '#2C2C2C',
19 | },
20 | settings: {
21 | display: 'flex',
22 | },
23 | })
24 | );
25 |
26 | interface NotificationPaneProps {
27 | value?: number;
28 | index?: number;
29 | }
30 |
31 | export default function NotificationPane(props: NotificationPaneProps) {
32 | const {value, index} = props;
33 | const classes = useStyles();
34 |
35 | return (
36 |
41 |
42 | Alert Notifications
43 |
44 |
45 | );
46 | }
47 |
--------------------------------------------------------------------------------
/spec/graphql/mutations/update_user_data.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | module Mutations
4 | RSpec.describe UpdateUserData, type: :request do
5 | describe '.resolve' do
6 | it 'updates a user details' do
7 | user = create(:user)
8 |
9 | expect do
10 | post '/graphql',
11 | params: { query: query(email: user.email, name: user.full_name) }
12 | post '/graphql',
13 | params: { query: query_update_user(name: 'Aijaz Khan') }
14 | it { expect(User.first.full_name).to eq 'Aijaz Khan' }
15 | end
16 | end
17 | end
18 |
19 | def query(email:, name:)
20 | <<~GQL
21 | mutation{
22 | signUpUser(
23 | email: #{email},
24 | fullName: #{
25 | name
26 | }
27 | ) {
28 | user {
29 | email
30 | }
31 | errors {
32 | path
33 | message
34 | }
35 | success
36 | }
37 | }
38 | GQL
39 | end
40 |
41 | def query_update_user(name:)
42 | <<~GQL
43 | mutation{
44 | updateUserData(
45 | fullName: #{
46 | name
47 | }
48 | ) {
49 | errors {
50 | path
51 | message
52 | }
53 | success
54 | }
55 | }
56 | GQL
57 | end
58 | end
59 | end
60 |
--------------------------------------------------------------------------------
/spec/graphql/mutations/update_company_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | module Mutations
4 | RSpec.describe UpdateCompanySettings, type: :request do
5 | describe '.resolve' do
6 | it 'update a company details' do
7 | company = create(:company)
8 | expect do
9 | post '/graphql', params: { query: query(name: company.name) }
10 | post '/graphql',
11 | params: {
12 | query:
13 | query_update_company(id: company.id, name: 'PrepDD-Test')
14 | }
15 | it { expect(Company.first.full_name).to eq 'PrepDD-Test' }
16 | end
17 | end
18 | end
19 |
20 | def query(name:)
21 | <<~GQL
22 | mutation{
23 | CreateCompany(
24 | name: #{
25 | name
26 | },
27 | ) {
28 | errors {
29 | path
30 | message
31 | }
32 | success
33 | }
34 | }
35 | GQL
36 | end
37 |
38 | def query_update_company(id:, name:)
39 | <<~GQL
40 | mutation{
41 | updateCompany(
42 | id: #{id},
43 | name: #{
44 | name
45 | }
46 | ) {
47 | errors {
48 | path
49 | message
50 | }
51 | success
52 | }
53 | }
54 | GQL
55 | end
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/common/DefaultUserImage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import clsx from 'clsx';
3 | import {Theme, makeStyles, createStyles} from '@material-ui/core/styles';
4 |
5 | const useStyles = makeStyles((theme: Theme) =>
6 | createStyles({
7 | root: {
8 | display: 'flex',
9 | width: '30px',
10 | height: '30px',
11 | position: 'relative',
12 | borderRadius: '50%',
13 | background: '#AFAFAF',
14 | alignItems: 'center',
15 | justifyContent: 'center',
16 | fontFamily: 'Montserrat',
17 | fontSize: '12px',
18 | fontWeight: 'bold',
19 | },
20 | label: {
21 | color: '#FFFFFF',
22 | },
23 | })
24 | );
25 |
26 | interface DefaultUserImageProps {
27 | className?: string;
28 | style?: React.CSSProperties;
29 | userName: string;
30 | }
31 |
32 | export default function DefaultUserImage(props: DefaultUserImageProps) {
33 | const {className, style, userName} = props;
34 | const classes = useStyles();
35 |
36 | return (
37 |
38 |
39 | {userName
40 | .split(' ')
41 | .slice(0, 2)
42 | .map(name => name[0])
43 | .join('')}
44 |
45 |
46 | );
47 | }
48 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/__generated__/CreateList.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | import { TaskAttributes } from "./../../__generated__/globalTypes";
6 |
7 | // ====================================================
8 | // GraphQL mutation operation: CreateList
9 | // ====================================================
10 |
11 | export interface CreateList_createList_list {
12 | __typename: "List";
13 | id: string;
14 | name: string | null;
15 | }
16 |
17 | export interface CreateList_createList_errors {
18 | __typename: "FormError";
19 | /**
20 | * Which field this error came from
21 | */
22 | path: string | null;
23 | /**
24 | * A description of the error
25 | */
26 | message: string;
27 | }
28 |
29 | export interface CreateList_createList {
30 | __typename: "CreateListPayload";
31 | list: CreateList_createList_list | null;
32 | errors: CreateList_createList_errors[];
33 | success: boolean;
34 | }
35 |
36 | export interface CreateList {
37 | createList: CreateList_createList | null;
38 | }
39 |
40 | export interface CreateListVariables {
41 | name: string;
42 | description?: string | null;
43 | requesterId: string;
44 | responderId: string;
45 | tasks?: TaskAttributes[] | null;
46 | }
47 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/queries/__generated__/UserDetails.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL query operation: UserDetails
7 | // ====================================================
8 |
9 | export interface UserDetails_user_roles {
10 | __typename: "RolesUser";
11 | id: string;
12 | name: string;
13 | companyId: string;
14 | }
15 |
16 | export interface UserDetails_user_teams {
17 | __typename: "Team";
18 | id: string;
19 | name: string;
20 | companyId: string;
21 | }
22 |
23 | export interface UserDetails_user_companies {
24 | __typename: "Company";
25 | id: string;
26 | name: string;
27 | logoUrl: string | null;
28 | }
29 |
30 | export interface UserDetails_user {
31 | __typename: "User";
32 | id: string;
33 | email: string;
34 | fullName: string;
35 | profileUrl: string | null;
36 | roles: UserDetails_user_roles[] | null;
37 | teams: UserDetails_user_teams[] | null;
38 | companies: UserDetails_user_companies[] | null;
39 | }
40 |
41 | export interface UserDetails {
42 | /**
43 | * Return details of a user
44 | */
45 | user: UserDetails_user;
46 | }
47 |
48 | export interface UserDetailsVariables {
49 | id: string;
50 | }
51 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/UpdateTask.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {UpdateTask, UpdateTaskVariables} from './__generated__/UpdateTask';
3 |
4 | export const useUpdateTask = createMutationHook<
5 | UpdateTask,
6 | UpdateTaskVariables
7 | >(gql`
8 | mutation UpdateTask(
9 | $id: ID!
10 | $name: String
11 | $description: String
12 | $priority: String
13 | $status: String
14 | $dueDate: String
15 | ) {
16 | updateTask(
17 | id: $id
18 | name: $name
19 | description: $description
20 | priority: $priority
21 | status: $status
22 | dueDate: $dueDate
23 | ) {
24 | success
25 | errors {
26 | path
27 | message
28 | }
29 | task {
30 | id
31 | name
32 | priority
33 | status
34 | dueDate
35 | updatedAt
36 | userOwners {
37 | id
38 | email
39 | fullName
40 | profileUrl
41 | }
42 | teamOwners {
43 | id
44 | name
45 | }
46 | userReviewers {
47 | id
48 | email
49 | fullName
50 | profileUrl
51 | }
52 | teamReviewers {
53 | id
54 | name
55 | }
56 | }
57 | }
58 | }
59 | `);
60 |
--------------------------------------------------------------------------------
/app/graphql/mutations/create_task.rb:
--------------------------------------------------------------------------------
1 | class Mutations::CreateTask < GraphQL::Schema::Mutation
2 | argument :listId, ID, required: true
3 | argument :tasks, [Types::TaskAttributes], required: true
4 |
5 | field :task, Types::TaskType, null: true
6 | field :errors, [Types::FormErrorType], null: false
7 | field :success, Boolean, null: false
8 |
9 | def resolve(list_id: nil, tasks: nil)
10 | response = { errors: [] }
11 |
12 | list = List.find(list_id)
13 |
14 | tasks.each do |task|
15 | # We want to set the list_number as the id of the last task in the list
16 | # plus one
17 | list_number =
18 | list.tasks.any? ? list.tasks.last.list_number + 1 : 1
19 | if task.section.present?
20 | task_section = TaskSection.where(name: task.section).first_or_create
21 | list.tasks.create(
22 | name: task.name,
23 | description: task.description,
24 | priority: task.priority,
25 | task_section_id: task_section&.id,
26 | list_number: list_number
27 | )
28 | else
29 | list.tasks.create(
30 | name: task.name,
31 | description: task.description,
32 | priority: task.priority,
33 | list_number: list_number
34 | )
35 | end
36 | end
37 |
38 | response[:success] = true
39 | response
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/app/javascript/src/application.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {render} from 'react-dom';
3 | import ApolloClient from 'apollo-client';
4 | import {ApolloProvider} from 'react-apollo';
5 | import {createHttpLink} from 'apollo-link-http';
6 | import {InMemoryCache} from 'apollo-cache-inmemory';
7 | import {ThemeProvider} from '@material-ui/styles';
8 | import CssBaseline from '@material-ui/core/CssBaseline';
9 | import App from './containers/app';
10 | import theme from './config/theme';
11 | import {Provider} from './store';
12 |
13 | function getCSRFToken(): string {
14 | const el = document.querySelector('meta[name="csrf-token"]');
15 | return (el && el.getAttribute('content')) || '';
16 | }
17 |
18 | document.addEventListener('DOMContentLoaded', () => {
19 | const link = createHttpLink({
20 | credentials: 'same-origin',
21 | headers: {
22 | 'X-CSRF-Token': getCSRFToken(),
23 | },
24 | });
25 |
26 | const client = new ApolloClient({
27 | link,
28 | cache: new InMemoryCache(),
29 | connectToDevTools: true,
30 | });
31 |
32 | render(
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | ,
41 | document.body.appendChild(document.createElement('div'))
42 | );
43 | });
44 |
--------------------------------------------------------------------------------
/app/graphql/mutations/remove_team_member.rb:
--------------------------------------------------------------------------------
1 | class Mutations::RemoveTeamMember < GraphQL::Schema::Mutation
2 | argument :teamId, ID, required: true
3 | argument :userId, ID, required: false
4 | argument :userIds, [ID], required: false
5 |
6 | field :user, Types::UserType, null: true
7 | field :teams, [Types::TeamType], null: true
8 | field :team, Types::TeamType, null: true
9 | field :companies, [Types::CompanyType], null: true
10 | field :role, Types::RoleType, null: true
11 | field :errors, [Types::FormErrorType], null: false
12 | field :success, Boolean, null: false
13 |
14 | def resolve(team_id: nil, user_id: nil, user_ids: nil)
15 | response = { errors: [] }
16 |
17 | if user_id
18 | TeamsUser.where(user_id: user_id, team_id: team_id).first&.destroy!
19 | elsif user_ids.present?
20 | user_ids.each do |id|
21 | TeamsUser.where(user_id: id, team_id: team_id).first&.destroy!
22 | end
23 | end
24 |
25 | company = Team.find(team_id)&.company
26 |
27 | user = User.find(user_id)
28 | teams = user.teams
29 | role = RolesUser.where(user_id: user.id, company_id: company.id).first.role
30 | companies = user.companies
31 |
32 | response[:success] = true
33 | response[:user] = user
34 | response[:companies] = companies
35 | response[:teams] = teams
36 | response[:role] = role
37 |
38 | response
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/AddTaskOwners.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {
3 | AddTaskOwners,
4 | AddTaskOwnersVariables,
5 | } from './__generated__/AddTaskOwners';
6 |
7 | export const useAddTaskOwners = createMutationHook<
8 | AddTaskOwners,
9 | AddTaskOwnersVariables
10 | >(gql`
11 | mutation AddTaskOwners(
12 | $taskID: ID!
13 | $userOwners: [String!]
14 | $userReviewers: [String!]
15 | $teamOwners: [ID!]
16 | $teamReviewers: [ID!]
17 | ) {
18 | addTaskOwners(
19 | taskID: $taskID
20 | userOwners: $userOwners
21 | userReviewers: $userReviewers
22 | teamOwners: $teamOwners
23 | teamReviewers: $teamReviewers
24 | ) {
25 | errors {
26 | path
27 | message
28 | }
29 | success
30 | task {
31 | id
32 | name
33 | priority
34 | status
35 | dueDate
36 | updatedAt
37 | userOwners {
38 | id
39 | email
40 | fullName
41 | profileUrl
42 | }
43 | teamOwners {
44 | id
45 | name
46 | }
47 | userReviewers {
48 | id
49 | email
50 | fullName
51 | profileUrl
52 | }
53 | teamReviewers {
54 | id
55 | name
56 | }
57 | }
58 | }
59 | }
60 | `);
61 |
--------------------------------------------------------------------------------
/app/controllers/graphql_controller.rb:
--------------------------------------------------------------------------------
1 | class GraphqlController < ApplicationController
2 | def execute
3 | variables = ensure_hash(params[:variables])
4 | query = params[:query]
5 | operation_name = params[:operationName]
6 | context = {
7 | # sign_out: sign_out
8 | session: session,
9 | # current_user: current_user,
10 | controller: self
11 | }
12 |
13 | result =
14 | PrepddSchema.execute(
15 | query,
16 | variables: variables, context: context, operation_name: operation_name
17 | )
18 | render json: result
19 | rescue => e
20 | raise e unless Rails.env.development?
21 | handle_error_in_development e
22 | end
23 |
24 | private
25 |
26 | # Handle form data, JSON body, or a blank value
27 | def ensure_hash(ambiguous_param)
28 | case ambiguous_param
29 | when String
30 | ambiguous_param.present? ? ensure_hash(JSON.parse(ambiguous_param)) : {}
31 | when Hash, ActionController::Parameters
32 | ambiguous_param
33 | when nil
34 | {}
35 | else
36 | raise ArgumentError, "Unexpected parameter: #{ambiguous_param}"
37 | end
38 | end
39 |
40 | def handle_error_in_development(e)
41 | logger.error e.message
42 | logger.error e.backtrace.join("\n")
43 |
44 | render json: {
45 | error: { message: e.message, backtrace: e.backtrace }, data: {}
46 | },
47 | status: 500
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/common/ConfirmModal.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Theme, makeStyles, createStyles} from '@material-ui/core/styles';
3 | import {Button} from '@material-ui/core';
4 | import Typography from '@material-ui/core/Typography';
5 | import WarningIcon from '@material-ui/icons/WarningRounded';
6 |
7 | const useStyles = makeStyles((theme: Theme) =>
8 | createStyles({
9 | root: {
10 | display: 'flex',
11 | width: '100%',
12 | alignItems: 'center',
13 | backgroundColor: 'rgba(248,231,28,0.20)',
14 | border: '1px solid #D8D8D8',
15 | borderRadius: '3px',
16 | marginTop: '12px',
17 | padding: '12px 20px',
18 | },
19 | })
20 | );
21 |
22 | interface ConfirmModalProps {
23 | confirmMessage: string;
24 | confirmAction: any;
25 | denyAction: any;
26 | }
27 |
28 | export default function ConfirmModal(props: ConfirmModalProps) {
29 | const classes = useStyles();
30 | const {confirmMessage, confirmAction, denyAction} = props;
31 |
32 | return (
33 |
34 |
35 |
36 | {confirmMessage}
37 |
38 |
41 |
44 |
45 | );
46 | }
47 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/SignUpUser.ts:
--------------------------------------------------------------------------------
1 | import {createMutationHook, gql} from '../graphqlHelpers';
2 | import {SignUpUser, SignUpUserVariables} from './__generated__/SignUpUser';
3 |
4 | export const useSignUpUser = createMutationHook<
5 | SignUpUser,
6 | SignUpUserVariables
7 | >(gql`
8 | mutation SignUpUser(
9 | $fullName: String!
10 | $email: String!
11 | $password: String!
12 | $companyName: String!
13 | $socialLogin: Boolean!
14 | $provider: String!
15 | $tokenID: String!
16 | $uuID: String!
17 | ) {
18 | signUpUser(
19 | fullName: $fullName
20 | email: $email
21 | password: $password
22 | companyName: $companyName
23 | socialLogin: $socialLogin
24 | provider: $provider
25 | tokenID: $tokenID
26 | uuID: $uuID
27 | ) {
28 | user {
29 | id
30 | email
31 | fullName
32 | displayName
33 | profileUrl
34 | lastViewedCompanyId
35 | ownedCompanies {
36 | id
37 | name
38 | }
39 | companies {
40 | id
41 | name
42 | logoUrl
43 | }
44 | teams {
45 | id
46 | companyId
47 | name
48 | }
49 | roles {
50 | id
51 | name
52 | companyId
53 | }
54 | }
55 | errors {
56 | path
57 | message
58 | }
59 | success
60 | }
61 | }
62 | `);
63 |
--------------------------------------------------------------------------------
/app/javascript/src/graphql/mutations/__generated__/SignInUser.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | // This file was automatically generated and should not be edited.
4 |
5 | // ====================================================
6 | // GraphQL mutation operation: SignInUser
7 | // ====================================================
8 |
9 | export interface SignInUser_signInUser_currentUser_user {
10 | __typename: "User";
11 | id: string;
12 | fullName: string;
13 | email: string;
14 | }
15 |
16 | export interface SignInUser_signInUser_currentUser {
17 | __typename: "CurrentUser";
18 | id: string;
19 | user: SignInUser_signInUser_currentUser_user | null;
20 | }
21 |
22 | export interface SignInUser_signInUser_errors {
23 | __typename: "FormError";
24 | /**
25 | * Which field this error came from
26 | */
27 | path: string | null;
28 | /**
29 | * A description of the error
30 | */
31 | message: string;
32 | }
33 |
34 | export interface SignInUser_signInUser {
35 | __typename: "SignInUserPayload";
36 | currentUser: SignInUser_signInUser_currentUser | null;
37 | errors: SignInUser_signInUser_errors[];
38 | success: boolean;
39 | }
40 |
41 | export interface SignInUser {
42 | signInUser: SignInUser_signInUser | null;
43 | }
44 |
45 | export interface SignInUserVariables {
46 | email: string;
47 | password: string;
48 | socialLogin: boolean;
49 | provider: string;
50 | tokenID: string;
51 | uuID: string;
52 | }
53 |
--------------------------------------------------------------------------------
/spec/graphql/mutations/create_team_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 | module Mutations
3 | RSpec.describe CreateTeam, type: :request do
4 | describe 'resolve' do
5 | it 'Create new Team' do
6 | company = create(:company)
7 | team = create(:team)
8 | expect do
9 | res =
10 | post '/graphql',
11 | params: { query: query_create_company(name: company.name) }
12 | res =
13 | post '/graphql',
14 | params: {
15 | query: query(company_id: company.id, name: team.name)
16 | }
17 | to change { Team.count }.by(1)
18 | it { expect Team.first.name.eql? team.name }
19 | it { expect Team.first.company_id.eql? company.id }
20 | end
21 | end
22 | end
23 |
24 | def query(company_id:, name:)
25 | <<~GQL
26 | mutation{
27 | CreateTeam(
28 | name: #{name},
29 | company_id: #{
30 | company_id
31 | }
32 | ) {
33 | errors {
34 | path
35 | message
36 | }
37 | success
38 | }
39 | }
40 | GQL
41 | end
42 |
43 | def query_create_company(name:)
44 | <<~GQL
45 | mutation{
46 | CreateCompany(
47 | name: #{
48 | name
49 | },
50 | ) {
51 | errors {
52 | path
53 | message
54 | }
55 | success
56 | }
57 | }
58 | GQL
59 | end
60 | end
61 | end
62 |
--------------------------------------------------------------------------------
/app/javascript/src/modules/team/components/TableHeader/TableHeader.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Theme, makeStyles, createStyles} from '@material-ui/core/styles';
3 | import TableHead from '@material-ui/core/TableHead';
4 |
5 | import StyledTableRow from '../styled/StyledTableRow';
6 | import StyledTableCell from '../styled/StyledTableCell';
7 |
8 | type roleType = 'Member' | 'Admin';
9 |
10 | interface Company {
11 | url: string;
12 | label: string;
13 | }
14 |
15 | interface Data {
16 | name: string;
17 | companies: Company[];
18 | teams: string[];
19 | role: roleType;
20 | }
21 |
22 | interface HeadRows {
23 | id: keyof Data;
24 | label: string;
25 | }
26 |
27 | const headRows: HeadRows[] = [
28 | {id: 'name', label: 'Name'},
29 | {id: 'companies', label: 'Company(s)'},
30 | {id: 'teams', label: 'Team(s)'},
31 | {id: 'role', label: 'Role'},
32 | ];
33 |
34 | const useStyles = makeStyles((theme: Theme) =>
35 | createStyles({
36 | root: {
37 | '& th:first-child': {
38 | paddingLeft: '31px',
39 | },
40 | },
41 | })
42 | );
43 |
44 | export default function TableHeader() {
45 | const classes = useStyles();
46 | return (
47 |
48 |
49 | {headRows.map(row => (
50 |
51 | {row.label}
52 |
53 | ))}
54 |
55 |
56 | );
57 | }
58 |
--------------------------------------------------------------------------------