diff --git a/app/controllers/client_api/configurations_controller.rb b/app/controllers/client_api/configurations_controller.rb new file mode 100644 index 000000000..30c623ba3 --- /dev/null +++ b/app/controllers/client_api/configurations_controller.rb @@ -0,0 +1,23 @@ +module ClientApi + class ConfigurationsController < ApplicationController + + def about_scinote + respond_to do |format| + format.json do + render json: { + scinoteVersion: Scinote::Application::VERSION, + addons: list_all_addons + }, status: :ok + end + end + end + + private + + def list_all_addons + Rails::Engine.subclasses + .select { |c| c.name.start_with?('Scinote') } + .map(&:parent) + end + end +end diff --git a/app/javascript/src/components/Navigation/components/AboutScinoteModal.jsx b/app/javascript/src/components/Navigation/components/AboutScinoteModal.jsx new file mode 100644 index 000000000..665b4cf2a --- /dev/null +++ b/app/javascript/src/components/Navigation/components/AboutScinoteModal.jsx @@ -0,0 +1,35 @@ +// @flow +import React from "react"; +import type { Node } from "react"; +import { FormattedMessage } from "react-intl"; +import { Modal } from "react-bootstrap"; + +type Props = { + showModal: boolean, + scinoteVersion: string, + addons: Array, + onModalClose: Function +}; + +export default (props: Props): Node => { + const { showModal, scinoteVersion, addons, onModalClose } = props; + return ( + + + + + + + + + + +

{scinoteVersion}

+ + + + {addons.map((addon: string): Node =>

{addon}

)} +
+
+ ); +}; diff --git a/app/javascript/src/components/Navigation/components/InfoDropdown.jsx b/app/javascript/src/components/Navigation/components/InfoDropdown.jsx index df063f0c6..e01328f56 100644 --- a/app/javascript/src/components/Navigation/components/InfoDropdown.jsx +++ b/app/javascript/src/components/Navigation/components/InfoDropdown.jsx @@ -1,4 +1,5 @@ -import React from "react"; +// @flow +import React, { Component } from "react"; import { FormattedMessage } from "react-intl"; import { NavDropdown, MenuItem } from "react-bootstrap"; import { @@ -8,35 +9,81 @@ import { PREMIUM_LINK, CONTACT_US_LINK } from "../../../config/routes"; +import { getSciNoteInfo } from "../../../services/api/configurations_api"; -const InfoDropdown = () => - -   - - - - - } - id="nav-info-dropdown" - > - - - - - - - - - - - - - - - - ; +import AboutScinoteModal from "./AboutScinoteModal"; + +type State = { + modalOpen: boolean, + scinoteVersion: string, + addons: Array +}; + +class InfoDropdown extends Component<*, State> { + constructor(props: any) { + super(props); + this.state = { showModal: false, scinoteVersion: "", addons: [] }; + (this: any).showAboutSciNoteModal = this.showAboutSciNoteModal.bind(this); + (this: any).closeModal = this.closeModal.bind(this); + } + + showAboutSciNoteModal(): void { + getSciNoteInfo().then(response => { + const { scinoteVersion, addons } = response; + (this: any).setState({ + scinoteVersion, + addons, + showModal: true + }); + }); + } + + closeModal(): void { + (this: any).setState({ showModal: false }); + } + + render() { + return ( + +   + + + + + } + id="nav-info-dropdown" + > + + + + + + + + + + + + + + + + + + + + + + ); + } +} export default InfoDropdown; diff --git a/app/javascript/src/config/locales/messages.js b/app/javascript/src/config/locales/messages.js index 4f6cd1389..88cef0ad6 100644 --- a/app/javascript/src/config/locales/messages.js +++ b/app/javascript/src/config/locales/messages.js @@ -6,7 +6,10 @@ export default { update: "Update", edit: "Edit", loading: "Loading ...", - upload: "Upload" + upload: "Upload", + about_scinote: "About sciNote", + core_version: "sciNote core version", + addon_versions: "Addon versions" }, page_title: { root: "SciNote", @@ -204,7 +207,8 @@ export default { tutorials: "Tutorials", release_notes: "Release notes", premium: "Premium", - contact_us: "Contact us" + contact_us: "Contact us", + about_scinote: "About sciNote" }, user_account_dropdown: { greeting: "Hi, {name}", diff --git a/app/javascript/src/services/api/configurations_api.js b/app/javascript/src/services/api/configurations_api.js new file mode 100644 index 000000000..0797ea244 --- /dev/null +++ b/app/javascript/src/services/api/configurations_api.js @@ -0,0 +1,6 @@ +// @flow +import axiosInstance from "./config"; +import { ABOUT_SCINOTE_PATH } from "./endpoints"; + +export const getSciNoteInfo = (): Promise<*> => + axiosInstance.get(ABOUT_SCINOTE_PATH).then(({ data }) => data); diff --git a/app/javascript/src/services/api/endpoints.js b/app/javascript/src/services/api/endpoints.js index 88c2002c1..f017c752e 100644 --- a/app/javascript/src/services/api/endpoints.js +++ b/app/javascript/src/services/api/endpoints.js @@ -36,3 +36,6 @@ export const INVITE_USERS_PATH = "/client_api/users/invite_users"; // settings export const SETTINGS_TEAMS = "/settings/teams"; + +// scinote configurations +export const ABOUT_SCINOTE_PATH = "/client_api/about_scinote"; diff --git a/config/routes.rb b/config/routes.rb index b00d30ee1..8d430a8f6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -18,7 +18,7 @@ Rails.application.routes.draw do get '/settings/*all', to: 'client_api/settings#index' namespace :client_api, defaults: { format: 'json' } do - %i(activities teams notifications users).each do |path| + %i(activities teams notifications users configurations).each do |path| draw path end end diff --git a/config/routes/configurations.rb b/config/routes/configurations.rb new file mode 100644 index 000000000..198449f22 --- /dev/null +++ b/config/routes/configurations.rb @@ -0,0 +1,2 @@ +# scinote configurations routes +get '/about_scinote', to: 'configurations#about_scinote' diff --git a/features/navigation/addons_versions_modal.feature b/features/navigation/addons_versions_modal.feature new file mode 100644 index 000000000..139004d33 --- /dev/null +++ b/features/navigation/addons_versions_modal.feature @@ -0,0 +1,21 @@ +Feature: Addon versions + As a sciNote User + I want know what addon are activated + So that I know what features are enabled + + Background: + Given the "BioSistemika Process" team exists + Given the following users are registered + | email | password | password_confirmation | full_name | initials | + | admin@myorg.com | mypassword1234 | mypassword1234 | Karli Novak | KN | + And "admin@myorg.com" is in "BioSistemika Process" team as a "admin" + And is signed in with "admin@myorg.com", "mypassword1234" + + @javascript + Scenario: Open the sciNote addons modal + Given I'm on the profile page + And I click "#nav-info-dropdown" icon + And I click "About sciNote" link within ".dropdown.open" + Then I should see "About sciNote" + And I should see "sciNote core version" + And I should see "Addon versions" diff --git a/features/settings_page/profile.feature b/features/settings_page/profile.feature index 25f70ce65..8d0e66647 100644 --- a/features/settings_page/profile.feature +++ b/features/settings_page/profile.feature @@ -15,7 +15,7 @@ Background: Scenario: Successful navigate to profile page Given I'm on the home page of "BioSistemika Process" team And I click on Avatar - And I click "Settings" link within "user-account-dropdown" + And I click "Settings" link within "#user-account-dropdown" Then I should see "My Profile" @javascript diff --git a/features/step_definitions/shared_steps.rb b/features/step_definitions/shared_steps.rb index 7a4d982df..4c122148b 100644 --- a/features/step_definitions/shared_steps.rb +++ b/features/step_definitions/shared_steps.rb @@ -15,7 +15,7 @@ Given(/^I click "(.+)" link$/) do |link| end Given(/^I click "(.+)" link within "(.+)"$/) do |link, element| - within("##{element}") do + within(element) do click_link link end end @@ -94,6 +94,10 @@ Then(/^I should see "([^"]*)" in "([^"]*)" input field$/) do |text, container_id expect(container).to have_xpath("//input[@value='#{text}']") end +Given("I click {string} icon") do |id| + find(:css, id).click +end + Then(/^(?:|I )click on "([^"]*)" element$/) do |selector| find(selector).click end @@ -116,5 +120,6 @@ Then(/^I change "([^"]*)" with "([^"]*)" in "([^"]*)" textarea field$/) do |old_ end Then(/^I should see "([^"]*)" on "([^"]*)" element$/) do |text, element| + wait_for_ajax expect(find(element)).to have_content(text) end diff --git a/spec/controllers/client_api/configurations_controller_spec.rb b/spec/controllers/client_api/configurations_controller_spec.rb new file mode 100644 index 000000000..a3c409138 --- /dev/null +++ b/spec/controllers/client_api/configurations_controller_spec.rb @@ -0,0 +1,10 @@ +require 'rails_helper' + +describe ClientApi::ConfigurationsController, type: :controller do + login_user + + describe '#about_scinote' do + let(:subject) { get :about_scinote, format: :json } + it { is_expected.to be_success } + end +end