diff --git a/Gemfile.lock b/Gemfile.lock index d61830cee8..127ad2c6d6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -107,40 +107,40 @@ GEM specs: aasm (5.5.0) concurrent-ruby (~> 1.0) - actioncable (6.1.7.8) - actionpack (= 6.1.7.8) - activesupport (= 6.1.7.8) + actioncable (6.1.7.9) + actionpack (= 6.1.7.9) + activesupport (= 6.1.7.9) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.1.7.8) - actionpack (= 6.1.7.8) - activejob (= 6.1.7.8) - activerecord (= 6.1.7.8) - activestorage (= 6.1.7.8) - activesupport (= 6.1.7.8) + actionmailbox (6.1.7.9) + actionpack (= 6.1.7.9) + activejob (= 6.1.7.9) + activerecord (= 6.1.7.9) + activestorage (= 6.1.7.9) + activesupport (= 6.1.7.9) mail (>= 2.7.1) - actionmailer (6.1.7.8) - actionpack (= 6.1.7.8) - actionview (= 6.1.7.8) - activejob (= 6.1.7.8) - activesupport (= 6.1.7.8) + actionmailer (6.1.7.9) + actionpack (= 6.1.7.9) + actionview (= 6.1.7.9) + activejob (= 6.1.7.9) + activesupport (= 6.1.7.9) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.1.7.8) - actionview (= 6.1.7.8) - activesupport (= 6.1.7.8) + actionpack (6.1.7.9) + actionview (= 6.1.7.9) + activesupport (= 6.1.7.9) rack (~> 2.0, >= 2.0.9) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.1.7.8) - actionpack (= 6.1.7.8) - activerecord (= 6.1.7.8) - activestorage (= 6.1.7.8) - activesupport (= 6.1.7.8) + actiontext (6.1.7.9) + actionpack (= 6.1.7.9) + activerecord (= 6.1.7.9) + activestorage (= 6.1.7.9) + activesupport (= 6.1.7.9) nokogiri (>= 1.8.5) - actionview (6.1.7.8) - activesupport (= 6.1.7.8) + actionview (6.1.7.9) + activesupport (= 6.1.7.9) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) @@ -148,27 +148,27 @@ GEM active_model_serializers (0.9.12) activemodel (>= 3.2) concurrent-ruby (~> 1.0) - activejob (6.1.7.8) - activesupport (= 6.1.7.8) + activejob (6.1.7.9) + activesupport (= 6.1.7.9) globalid (>= 0.3.6) activejob-status (1.0.2) activejob (>= 6.0) activesupport (>= 6.0) - activemodel (6.1.7.8) - activesupport (= 6.1.7.8) - activerecord (6.1.7.8) - activemodel (= 6.1.7.8) - activesupport (= 6.1.7.8) + activemodel (6.1.7.9) + activesupport (= 6.1.7.9) + activerecord (6.1.7.9) + activemodel (= 6.1.7.9) + activesupport (= 6.1.7.9) activerecord-nulldb-adapter (1.0.1) activerecord (>= 5.2.0, < 7.2) - activestorage (6.1.7.8) - actionpack (= 6.1.7.8) - activejob (= 6.1.7.8) - activerecord (= 6.1.7.8) - activesupport (= 6.1.7.8) + activestorage (6.1.7.9) + actionpack (= 6.1.7.9) + activejob (= 6.1.7.9) + activerecord (= 6.1.7.9) + activesupport (= 6.1.7.9) marcel (~> 1.0) mini_mime (>= 1.1.0) - activesupport (6.1.7.8) + activesupport (6.1.7.9) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) @@ -392,7 +392,7 @@ GEM csv mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) - i18n (1.14.5) + i18n (1.14.6) concurrent-ruby (~> 1.0) icalendar (2.10.2) ice_cube (~> 0.16) @@ -480,7 +480,7 @@ GEM ruby2_keywords (~> 0.0.1) mustermann-grape (1.0.2) mustermann (>= 1.0.0) - net-imap (0.4.14) + net-imap (0.4.17) date net-protocol net-pop (0.1.2) @@ -596,20 +596,20 @@ GEM rack rack-test (2.1.0) rack (>= 1.3) - rails (6.1.7.8) - actioncable (= 6.1.7.8) - actionmailbox (= 6.1.7.8) - actionmailer (= 6.1.7.8) - actionpack (= 6.1.7.8) - actiontext (= 6.1.7.8) - actionview (= 6.1.7.8) - activejob (= 6.1.7.8) - activemodel (= 6.1.7.8) - activerecord (= 6.1.7.8) - activestorage (= 6.1.7.8) - activesupport (= 6.1.7.8) + rails (6.1.7.9) + actioncable (= 6.1.7.9) + actionmailbox (= 6.1.7.9) + actionmailer (= 6.1.7.9) + actionpack (= 6.1.7.9) + actiontext (= 6.1.7.9) + actionview (= 6.1.7.9) + activejob (= 6.1.7.9) + activemodel (= 6.1.7.9) + activerecord (= 6.1.7.9) + activestorage (= 6.1.7.9) + activesupport (= 6.1.7.9) bundler (>= 1.15.0) - railties (= 6.1.7.8) + railties (= 6.1.7.9) sprockets-rails (>= 2.0.0) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) @@ -618,9 +618,9 @@ GEM rails-html-sanitizer (1.6.0) loofah (~> 2.21) nokogiri (~> 1.14) - railties (6.1.7.8) - actionpack (= 6.1.7.8) - activesupport (= 6.1.7.8) + railties (6.1.7.9) + actionpack (= 6.1.7.9) + activesupport (= 6.1.7.9) method_source rake (>= 12.2) thor (~> 1.0) @@ -847,7 +847,7 @@ GEM rails (>= 3.0) rake (>= 0.8.7) yard (0.9.36) - zeitwerk (2.6.17) + zeitwerk (2.6.18) PLATFORMS x86_64-linux diff --git a/app/api/chemotion/ui_api.rb b/app/api/chemotion/ui_api.rb index 28f9f4b9f1..3c56a7c545 100644 --- a/app/api/chemotion/ui_api.rb +++ b/app/api/chemotion/ui_api.rb @@ -31,6 +31,7 @@ class UiAPI < Grape::API molecule_viewer: Matrice.molecule_viewer, collector_address: collector_address.presence, third_party_apps: Entities::ThirdPartyAppEntity.represent(ThirdPartyApp.all), + version: Chemotion::Application.config.version, } end end diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 5d0bb66ab0..737d165c30 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -1,7 +1,7 @@ /* * In order to control import order and provide access to variables, mixins and utilities, we import * the files within this directory manually via sass `@import`, instead of using `require_tree .` - * + * * The files in the legacy directory have not yet been aligned with the design system initiative and * will be refactored in the future. * @@ -25,6 +25,7 @@ @import "components/Report"; @import "components/SearchModal"; @import "components/SearchResult"; +@import "components/SideBar"; @import "components/QuillEditor"; @import "components/QuillViewer"; @import "components/Styleguide"; diff --git a/app/assets/stylesheets/components/QuillEditor.css b/app/assets/stylesheets/components/QuillEditor.css index ffa480625d..88bd452a3c 100644 --- a/app/assets/stylesheets/components/QuillEditor.css +++ b/app/assets/stylesheets/components/QuillEditor.css @@ -456,6 +456,11 @@ .ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter { stroke: $primary; } +.ql-snow .ql-picker .ql-picker-label::before, .ql-snow .ql-picker.ql-size .ql-picker-item::before { + content: attr(data-label); + line-height: 25px; +} + .ql-snow { box-sizing: border-box; } diff --git a/app/assets/stylesheets/components/Sidebar.scss b/app/assets/stylesheets/components/Sidebar.scss new file mode 100644 index 0000000000..d9182cf91a --- /dev/null +++ b/app/assets/stylesheets/components/Sidebar.scss @@ -0,0 +1,36 @@ +.sidebar { + @extend .text-bg-white; + @extend .position-relative; + @extend .p-3; + width: 300px; + &.sidebar--collapsed { + width: 80px; + } +} + +$sidebar-button-diameter: 16px; + +.sidebar-collapse-button-container { + @extend .position-absolute; + @extend .end-0; + @extend .overflow-hidden; + top: calc(50% - #{$sidebar-button-diameter}); + width: $sidebar-button-diameter; + margin: auto -14px auto 0; + z-index: 1000; +} + +.sidebar-collapse-button { + @extend .rounded-start-0; + @extend .btn-sm; + @extend .p-2; + @extend .text-end; + @extend .text-primary; + @extend .border; + background-color: $white !important; + margin-left: -$sidebar-button-diameter; + border-top-right-radius: 100% !important; + border-bottom-right-radius: 100% !important; + width: $sidebar-button-diameter * 2; + height: $sidebar-button-diameter * 2; +} diff --git a/app/assets/stylesheets/global-styles/bootstrap-config.scss b/app/assets/stylesheets/global-styles/bootstrap-config.scss index 57410b52bf..d0eb83fdf2 100644 --- a/app/assets/stylesheets/global-styles/bootstrap-config.scss +++ b/app/assets/stylesheets/global-styles/bootstrap-config.scss @@ -4,6 +4,7 @@ $success: $chemstrap-green; $info: #5bc0de; // to be removed application wide $warning: $chemstrap-yellow; $danger: $chemstrap-red; +$white: white; $zindex-levels: ( n1: -1, @@ -17,6 +18,7 @@ $zindex-levels: ( $chemstrap-theme-colors: ( "active": $chemstrap-blue-dark, + "white": $white, ); @import "bootstrap/functions"; diff --git a/app/assets/stylesheets/global-styles/bootstrap-mods.scss b/app/assets/stylesheets/global-styles/bootstrap-mods.scss index 4fcee79b87..d921859e5c 100644 --- a/app/assets/stylesheets/global-styles/bootstrap-mods.scss +++ b/app/assets/stylesheets/global-styles/bootstrap-mods.scss @@ -38,7 +38,7 @@ $button-variant-colors: ( map-get(map-get($button-variant-colors, $name), "text-active"), map-get(map-get($button-variant-colors, $name), "bg-default"), map-get(map-get($button-variant-colors, $name), "bg-default"), - map-get(map-get($button-variant-colors, $name), "text-default"), + map-get(map-get($button-variant-colors, $name), "text-default") ); } @@ -72,19 +72,26 @@ $button-variant-colors: ( } .input-group-xsm > { - .form-control, .form-select, .input-group-text, .btn { + .form-control, + .form-select, + .input-group-text, + .btn { @include xsm-form-elements; } } .input-group-xxsm > { - .form-control, .form-select, .input-group-text, .btn { + .form-control, + .form-select, + .input-group-text, + .btn { @include xxsm-form-elements; } } .popover-header:not(:first-child) { - border-top: var(--bs-popover-border-width) solid var(--bs-popover-border-color); + border-top: var(--bs-popover-border-width) solid + var(--bs-popover-border-color); border-radius: 0; } diff --git a/app/assets/stylesheets/global-styles/package-mods/react-select.scss b/app/assets/stylesheets/global-styles/package-mods/react-select.scss index 64ece59be0..aae15da803 100644 --- a/app/assets/stylesheets/global-styles/package-mods/react-select.scss +++ b/app/assets/stylesheets/global-styles/package-mods/react-select.scss @@ -22,11 +22,13 @@ .chemotion-select { position: relative; &.is-invalid { - .chemotion-select__control, .chemotion-select__control:hover { + .chemotion-select__control, + .chemotion-select__control:hover { border-color: $danger; } } - &__control, &__menu { + &__control, + &__menu { @extend .d-block; @extend .w-100; padding: $form-select-padding-y $form-select-padding-x; @@ -57,11 +59,15 @@ border-color: color("primary"); } - &:focus, &--is-focused { + &:focus, + &--is-focused { border-color: $input-focus-border-color; outline: 0; @if $enable-shadows { - @include box-shadow($form-select-box-shadow, $form-select-focus-box-shadow); + @include box-shadow( + $form-select-box-shadow, + $form-select-focus-box-shadow + ); } @else { // Avoid using mixin so we can pass custom focus shadow properly box-shadow: $form-select-focus-box-shadow; @@ -74,30 +80,41 @@ background-image: none; } - &:disabled, &--is-disabled { + &:disabled, + &--is-disabled { color: $form-select-disabled-color; background-color: $form-select-disabled-bg; border-color: $form-select-disabled-border-color; } } + &__value-container { + @extend .flex-nowrap; + @extend .text-nowrap; + @extend .gap-1; + @extend .d-flex; + } - &__indicator, &__value-container, &__input-container, &__placeholder, &__single-value, &__indicator-separator { + &__indicator, + &__value-container, + &__input-container, + &__placeholder, + &__single-value, + &__indicator-separator { @extend .p-0; @extend .m-0; } - &__value-container { - @extend .gap-1; - @extend .d-flex; + &__value-container.chemotion-select__value-container--is-multi { + @extend .flex-wrap; + @extend .text-wrap; } &__single-value .badge { - @extend .d-block + @extend .d-block; } &__indicator { - &-separator { @extend .d-none; } @@ -122,7 +139,8 @@ &__option { padding: $form-select-padding-y $form-select-padding-x; - &--is-selected, &--is-selected.chemotion-select__option--is-focused { + &--is-selected, + &--is-selected.chemotion-select__option--is-focused { background-color: color("primary"); } @@ -149,5 +167,4 @@ &__clear-indicator { @include fa-based-remove-icon; } - } diff --git a/app/packs/src/apps/mydb/App.js b/app/packs/src/apps/mydb/App.js index 1a6282d641..be1dd854a6 100644 --- a/app/packs/src/apps/mydb/App.js +++ b/app/packs/src/apps/mydb/App.js @@ -119,22 +119,17 @@ class App extends Component { renderContent() { const { isSidebarCollapsed } = this.state; - const sidebarCols = isSidebarCollapsed ? 1 : 2; return ( - - - - - - - - {this.mainContent()} - - - +
+ +
+ + {this.mainContent()} +
+
); } diff --git a/app/packs/src/apps/mydb/inbox/InboxModal.js b/app/packs/src/apps/mydb/inbox/InboxModal.js index 7eb4d2ce50..1a3e8dc993 100644 --- a/app/packs/src/apps/mydb/inbox/InboxModal.js +++ b/app/packs/src/apps/mydb/inbox/InboxModal.js @@ -55,12 +55,6 @@ export default class InboxModal extends React.Component { InboxActions.fetchInboxCount(); } - componentWillUnmount() { - InboxStore.unlisten(this.onInboxStoreChange); - UIStore.unlisten(this.onUIStoreChange); - UserStore.unlisten(this.onUserStoreChange); - } - componentDidUpdate(prevProps, prevState) { const { currentPage, itemsPerPage } = this.state; if (prevState.currentPage !== currentPage @@ -69,6 +63,12 @@ export default class InboxModal extends React.Component { } } + componentWillUnmount() { + InboxStore.unlisten(this.onInboxStoreChange); + UIStore.unlisten(this.onUIStoreChange); + UserStore.unlisten(this.onUserStoreChange); + } + handlePageChange(pageNumber) { const { totalPages } = this.state; if (pageNumber > 0 && pageNumber <= totalPages) { @@ -93,7 +93,12 @@ export default class InboxModal extends React.Component { onUserStoreChange(state) { const type = 'inbox'; const filters = state?.profile?.data?.filters || {}; - this.setState({sortColumn: filters[type]?.sort || 'name'}); + const newSortColumn = filters[type]?.sort || 'name'; + + const { sortColumn } = this.state; + if (sortColumn !== newSortColumn) { + this.setState({ sortColumn: newSortColumn }); + } } onClickInbox() { diff --git a/app/packs/src/apps/mydb/layout/Sidebar.js b/app/packs/src/apps/mydb/layout/Sidebar.js index 13314c5cdc..9a733e604a 100644 --- a/app/packs/src/apps/mydb/layout/Sidebar.js +++ b/app/packs/src/apps/mydb/layout/Sidebar.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { Button } from 'react-bootstrap'; import classNames from 'classnames'; -import NavHead from 'src/components/navigation/NavHead'; +import ChemotionLogo from 'src/components/common/ChemotionLogo'; import CollectionTree from 'src/apps/mydb/collections/CollectionTree'; import CollectionManagementButton from 'src/apps/mydb/collections/CollectionManagementButton'; @@ -14,37 +14,34 @@ import NoticeButton from 'src/components/contextActions/NoticeButton'; export default function Sidebar({ isCollapsed, toggleCollapse }) { return ( -
-
-
- -
+
+
- {!isCollapsed && ( - - )} -
-
- - - - - +
+ + + +
+ {!isCollapsed && ( + + )} + +
+
+ + + + +
); diff --git a/app/packs/src/apps/mydb/layout/Topbar.js b/app/packs/src/apps/mydb/layout/Topbar.js index 3a2a00ceb8..d892b82f43 100644 --- a/app/packs/src/apps/mydb/layout/Topbar.js +++ b/app/packs/src/apps/mydb/layout/Topbar.js @@ -7,6 +7,7 @@ import SplitElementButton from 'src/components/contextActions/SplitElementButton import ReportUtilButton from 'src/components/contextActions/ReportUtilButton'; import ExportImportButton from 'src/components/contextActions/ExportImportButton'; import ScanCodeButton from 'src/components/contextActions/ScanCodeButton'; +import SupportMenuButton from 'src/components/navigation/SupportMenuButton'; import UserAuth from 'src/components/navigation/UserAuth'; export default function Topbar() { @@ -24,6 +25,7 @@ export default function Topbar() { +
diff --git a/app/packs/src/components/common/ChemotionLogo.js b/app/packs/src/components/common/ChemotionLogo.js new file mode 100644 index 0000000000..9e35a4e999 --- /dev/null +++ b/app/packs/src/components/common/ChemotionLogo.js @@ -0,0 +1,113 @@ +import React from 'react'; + +const ChemotionLogo = ({ collapsed }) => { + const width = collapsed ? "60" : "100"; + + const styles = { + blue: { + fill: "#2495cf", + }, + red: { + fill: "#f55", + }, + grey: { + fill: "#4f5659", + }, + }; + + return ( + + Chemotion Logo + + + ); +}; + +export default ChemotionLogo; diff --git a/app/packs/src/components/common/Select.js b/app/packs/src/components/common/Select.js index 9a1cb46d18..1f8ac45be5 100644 --- a/app/packs/src/components/common/Select.js +++ b/app/packs/src/components/common/Select.js @@ -1,24 +1,27 @@ -import React from 'react'; +import React, { forwardRef } from 'react'; import RSelect from 'react-select'; import RAsyncSelect from 'react-select/async'; import RCreatableSelect from 'react-select/creatable'; /* eslint-disable react/jsx-props-no-spreading */ - // deactivate the default styling and apply custom class names to enable bootstrap styling - // see https://react-select.com/styles#the-unstyled-prop - // see https://react-select.com/styles#the-classnameprefix-prop +// deactivate the default styling and apply custom class names to enable bootstrap styling +// see https://react-select.com/styles#the-unstyled-prop +// see https://react-select.com/styles#the-classnameprefix-prop -export const Select = ({className, ...props}) => ( - -); +export const Select = forwardRef(function Select(props, ref) { + return ( + + ); +}); -export const AsyncSelect = ({className, ...props}) => ( +export const AsyncSelect = ({ className, ...props }) => ( ( /> ); -export const CreatableSelect = ({className, ...props}) => ( +export const CreatableSelect = ({ className, ...props }) => ( - ); + return ( + + ); } render() { @@ -51,16 +51,16 @@ class ContainerDatasetField extends Component { } const gdsDownload = (datasetContainer.dataset == null || typeof datasetContainer.dataset === 'undefined') ? () : ( - download metadata}> - - - ); + download metadata}> + + + ); return connectDropTarget(
{datasetContainer.dataset && datasetContainer.dataset.klass_ols !== absOlsTermId(kind) @@ -100,7 +100,7 @@ ContainerDatasetField.propTypes = { id: PropTypes.number, }).isRequired, handleUndo: PropTypes.func.isRequired, - kind: PropTypes.string.isRequired, + kind: PropTypes.string, handleModalOpen: PropTypes.func.isRequired, }; diff --git a/app/packs/src/components/contextActions/SplitElementButton.js b/app/packs/src/components/contextActions/SplitElementButton.js index 93a22f855c..21578b12fa 100644 --- a/app/packs/src/components/contextActions/SplitElementButton.js +++ b/app/packs/src/components/contextActions/SplitElementButton.js @@ -9,26 +9,71 @@ import MatrixCheck from 'src/components/common/MatrixCheck'; export default class SplitElementButton extends React.Component { constructor(props) { super(props); + + const uiState = UIStore.getState(); + const userState = UserStore.getState(); this.state = { - layout: UserStore.getState().profile?.data?.layout || {}, + currentCollection: uiState.currentCollection, + currentUser: {}, + genericEls: [], + showGenericEls: MatrixCheck(userState.currentUser?.matrix, 'genericEl'), + layout: {}, + selectedElements: {}, }; - this.onChange = this.onChange.bind(this); + this.onUserStoreChange = this.onUserStoreChange.bind(this); + this.onUIStoreChange = this.onUIStoreChange.bind(this); } componentDidMount() { - UserStore.listen(this.onChange); + UserStore.listen(this.onUserStoreChange); + UIStore.listen(this.onUIStoreChange); + this.onUserStoreChange(UserStore.getState()); + this.onUIStoreChange(UIStore.getState()); } componentWillUnmount() { - UserStore.unlisten(this.onChange); + UserStore.unlisten(this.onUserStoreChange); + UIStore.unlisten(this.onUIStoreChange); + } + + onUserStoreChange(state) { + const { layout, showGenericEls, genericEls } = this.state; + const newLayout = state.profile?.data?.layout; + const newCurrentUser = state.currentUser; + const newGenericEls = state.genericEls; + + if (typeof newLayout !== 'undefined' && newLayout !== null && newLayout !== layout) { + this.setState({ layout: newLayout }); + } + + const newShowGenericEls = MatrixCheck(newCurrentUser?.matrix, 'genericEl'); + if (newShowGenericEls !== showGenericEls) { + this.setState({ currentUser: newCurrentUser }); + } + + if (newGenericEls !== genericEls) { + this.setState({ genericEls: newGenericEls }); + } } - onChange(state) { - const layout = state.profile?.data?.layout; - // eslint-disable-next-line react/destructuring-assignment - if (typeof layout !== 'undefined' && layout !== null && layout !== this.state.layout) { - this.setState({ layout }); + onUIStoreChange(state) { + const { currentCollection, genericEls, selectedElements } = this.state; + const { currentCollection: newCurrentCollection } = state; + if (newCurrentCollection !== currentCollection) { + this.setState({ currentCollection: newCurrentCollection }); + } + + const newSelectedElements = ['sample', 'wellplate', ...genericEls.map((el) => el.name)].reduce( + (acc, el) => { + const { checkedIds, checkedAll } = state[el] || {}; + const hasSelected = checkedIds?.size > 0 || checkedAll === true; + return { ...acc, [el]: hasSelected }; + }, + {} + ); + if (JSON.stringify(newSelectedElements) !== JSON.stringify(selectedElements)) { + this.setState({ selectedElements: newSelectedElements }); } } @@ -41,12 +86,12 @@ export default class SplitElementButton extends React.Component { } noSelected(name) { - const state = UIStore.getState() || {}; - return state[name]?.checkedIds?.size === 0 && state[name]?.checkedAll === false; + const { selectedElements } = this.state; + return !selectedElements[name]; } isAllCollection() { - const { currentCollection } = UIStore.getState(); + const { currentCollection } = this.state; return currentCollection && currentCollection.label === 'All'; } @@ -55,39 +100,41 @@ export default class SplitElementButton extends React.Component { } render() { - const { layout } = this.state; - let genericEls = []; - const currentUser = (UserStore.getState() && UserStore.getState().currentUser) || {}; - if (MatrixCheck(currentUser.matrix, 'genericElement')) { - genericEls = UserStore.getState().genericEls || []; - } + const { layout, genericEls, showGenericEls, selectedElements } = this.state; + const sortedLayout = Object.entries(layout) .filter((o) => o[1] && o[1] > 0) .sort((a, b) => a[1] - b[1]); const sortedGenericEls = []; - sortedLayout.forEach(([k]) => { - const el = genericEls.find((ael) => ael.name === k); - if (typeof el !== 'undefined') { - sortedGenericEls.push(el); - } - }); + if (showGenericEls) { + sortedLayout.forEach(([k]) => { + const el = genericEls.find((ael) => ael.name === k); + if (typeof el !== 'undefined') { + sortedGenericEls.push(el); + } + }); + } + + const isDisabled = this.isAllCollection() + || Object.values(selectedElements).every((v) => !v); return ( } + disabled={isDisabled} > this.splitSelectionAsSubsamples()} - disabled={this.noSelected('sample') || this.isAllCollection()} + disabled={!selectedElements['sample']} > Split Sample this.splitSelectionAsSubwellplates()} - disabled={this.noSelected('wellplate') || this.isAllCollection()} + disabled={!selectedElements['wellplate']} > Split Wellplate @@ -96,9 +143,10 @@ export default class SplitElementButton extends React.Component { id={`split-${el.name}-button`} key={el.name} onClick={() => this.splitElements(`${el.name}`)} - disabled={this.noSelected(el.name) || this.isAllCollection()} + disabled={!selectedElements[el.name]} > Split + {' '} {el.label} ))} diff --git a/app/packs/src/components/navigation/NavHead.js b/app/packs/src/components/navigation/NavHead.js index f8488ae71a..67db070266 100644 --- a/app/packs/src/components/navigation/NavHead.js +++ b/app/packs/src/components/navigation/NavHead.js @@ -1,41 +1,49 @@ import React from 'react'; -import { NavDropdown, Dropdown } from 'react-bootstrap'; - -function ExternalLinkItem({ text, href }) { - return ( - - {text} - - - ); -} +import { NavDropdown, Navbar, Dropdown } from 'react-bootstrap'; function NavHead() { const isOnMydb = window.location.href.match(/\/mydb/); return ( - - - - - - - - - - - - {isOnMydb ? 'Home' : 'ELN'} - - - About - - + + + + Documentation +