mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-12-09 13:46:21 +08:00
Merge remote-tracking branch 'upstream/ux-release-1' into ml-sci-2118
This commit is contained in:
commit
884eef9d07
24 changed files with 946 additions and 781 deletions
|
|
@ -198,9 +198,6 @@ var HelperModule = (function(){
|
|||
window.setTimeout(function () {
|
||||
flash.fadeTo(500, 0).slideUp(500, function () {
|
||||
$(this).remove();
|
||||
if($('.alert').length <= 0) {
|
||||
$('#content-wrapper').removeClass('alert-shown');
|
||||
}
|
||||
});
|
||||
}, 5000);
|
||||
}
|
||||
|
|
@ -234,7 +231,6 @@ var HelperModule = (function(){
|
|||
'</div>' +
|
||||
'</div>';
|
||||
$('#notifications').html(htmlSnippet);
|
||||
$('#content-wrapper').addClass('alert-shown');
|
||||
helpers.hideFlashMsg();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,20 +94,9 @@
|
|||
});
|
||||
}
|
||||
|
||||
function focusSearchInput() {
|
||||
var searchIco = $('#search-ico');
|
||||
searchIco
|
||||
.on('shown.bs.dropdown', function() {
|
||||
searchIco
|
||||
.find('input.form-control')
|
||||
.focus();
|
||||
});
|
||||
}
|
||||
|
||||
// init
|
||||
loadDropdownNotifications();
|
||||
loadUnseenNotificationsNumber();
|
||||
toggleNotificationBellPosition();
|
||||
focusSearchInput();
|
||||
initGlobalSwitchForm();
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ $(document).ready(function () {
|
|||
$("#hide-alert").click(function(ev) {
|
||||
$(this).closest("div.alert").addClass("alert-hidden");
|
||||
$("#content-wrapper").addClass("alert-hidden");
|
||||
$("#content-wrapper").removeClass("alert-shown");
|
||||
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@
|
|||
//==============================================================================
|
||||
|
||||
// Theme colors
|
||||
$color-theme-primary: #37a0d9;
|
||||
$color-theme-primary: #41B0E0;
|
||||
$color-theme-secondary: #8fd13f;
|
||||
$color-theme-dark: #6d6e71;
|
||||
|
||||
// Grayscale colors
|
||||
$color-border: #DDDDDD;
|
||||
$color-list-separator: #BDC3C7;
|
||||
$color-white: #fff;
|
||||
$color-alabaster: #fcfcfc;
|
||||
$color-snow: #f9f9f9;
|
||||
|
|
@ -34,6 +36,7 @@ $color-mystic: #eaeff2;
|
|||
$color-candlelight: #ffda23;
|
||||
$color-orange: #ff900b;
|
||||
$color-saturated-green: #008600;
|
||||
$color-confirmation-green: #25AE88;
|
||||
$color-blue-yadcf: #337ab7;
|
||||
|
||||
// Red colors
|
||||
|
|
|
|||
2
app/assets/stylesheets/extend/bootstrap.scss
vendored
2
app/assets/stylesheets/extend/bootstrap.scss
vendored
|
|
@ -58,7 +58,7 @@
|
|||
float: none;
|
||||
}
|
||||
|
||||
@media (max-width: 1000px) {
|
||||
@media (max-width: 1188px) {
|
||||
.navbar-header {
|
||||
float: none;
|
||||
}
|
||||
|
|
|
|||
114
app/assets/stylesheets/themes/buttons.scss
Normal file
114
app/assets/stylesheets/themes/buttons.scss
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
@import 'constants';
|
||||
@import "mixins";
|
||||
|
||||
|
||||
#reset-tutorial-btn {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: $color-theme-secondary;
|
||||
border-color: darken($color-theme-secondary, 5%);
|
||||
|
||||
&.active,
|
||||
&.focus,
|
||||
&.active.focus {
|
||||
background-color: darken($color-theme-secondary, 20%);
|
||||
border-color: darken($color-theme-secondary, 25%);
|
||||
|
||||
&:hover {
|
||||
background-color: darken($color-theme-secondary, 25%);
|
||||
border-color: darken($color-theme-secondary, 30%);
|
||||
}
|
||||
}
|
||||
|
||||
&:active,
|
||||
&:focus,
|
||||
&:active:focus,
|
||||
&:active:hover,
|
||||
&:focus:hover,
|
||||
&:active:focus:hover {
|
||||
background-color: darken($color-theme-secondary, 20%);
|
||||
border-color: darken($color-theme-secondary, 25%);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: darken($color-theme-secondary, 5%);
|
||||
border-color: darken($color-theme-secondary, 10%);
|
||||
}
|
||||
}
|
||||
.btn-link-alt {
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-right: 5px;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.btn-invis-file {
|
||||
display: none;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.btn-open-file {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
& > input[type=file] {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
font-size: 100px;
|
||||
text-align: right;
|
||||
filter: alpha(opacity=0);
|
||||
opacity: 0;
|
||||
outline: none;
|
||||
background: white;
|
||||
cursor: inherit;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
/** Add users modal */
|
||||
.btn-group-existing-users {
|
||||
width: 100%;
|
||||
|
||||
label.btn {
|
||||
text-align: center;
|
||||
|
||||
&.btn-title {
|
||||
color: $color-white;
|
||||
cursor: inherit;
|
||||
background-color: $color-theme-primary;
|
||||
|
||||
&:focus, &:active, &:hover {
|
||||
box-shadow: none;
|
||||
background-color: $color-theme-primary;
|
||||
border-color: $color-dark-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-greyed {
|
||||
background-color: $color-silver-chalice;
|
||||
border-color: $color-silver-chalice;
|
||||
color: $color-white;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: darken($color-silver-chalice, 15%);
|
||||
border-color: darken($color-silver-chalice, 15%);
|
||||
color: $color-white;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sample group color picker */
|
||||
.btn-group-sample-group-color {
|
||||
.btn-group > .btn {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
}
|
||||
380
app/assets/stylesheets/themes/main_navigation.scss
Normal file
380
app/assets/stylesheets/themes/main_navigation.scss
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
@import 'constants';
|
||||
@import "mixins";
|
||||
|
||||
#main-nav {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#notifications-dropdown {
|
||||
.fa-bell {
|
||||
font-size: 15px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#count-notifications {
|
||||
background-color: $color-theme-primary;
|
||||
border-radius: 5px;
|
||||
color: $color-wild-sand;
|
||||
display: none;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
margin-left: 12px;
|
||||
padding: 1px 6px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar {
|
||||
border-radius: 0;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.navbar-default {
|
||||
background-color: $color-white;
|
||||
border-color: $color-alto;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-brand {
|
||||
& > img {
|
||||
margin-top: -7px;
|
||||
max-width: 55px;
|
||||
max-height: 38px;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-notifications {
|
||||
max-height: 500px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
padding-bottom: 0;
|
||||
padding-top: 0;
|
||||
width: 450px;
|
||||
word-wrap: break-word;
|
||||
|
||||
.notifications-no-recent {
|
||||
padding-bottom: 10px;
|
||||
padding-left: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.notification {
|
||||
border-bottom: 1px solid $color-alto;
|
||||
padding-bottom: 10px;
|
||||
padding-top: 10px;
|
||||
|
||||
&:hover {
|
||||
background-color: $color-concrete;
|
||||
}
|
||||
}
|
||||
|
||||
.unseen {
|
||||
border-left: 4px solid $color-theme-primary;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
top: 0px;
|
||||
margin-top: 5px;
|
||||
height: 45px;
|
||||
width: 45px;
|
||||
}
|
||||
|
||||
.assignment {
|
||||
background-color: $color-theme-primary;
|
||||
border-radius: 50%;
|
||||
color: $color-wild-sand;
|
||||
display: block;
|
||||
font-size: 23px;
|
||||
height: 45px;
|
||||
padding-top: 5px;
|
||||
width: 45px;
|
||||
}
|
||||
|
||||
.deliver {
|
||||
background-color: $color-orange;
|
||||
border-radius: 50%;
|
||||
color: $color-wild-sand;
|
||||
display: block;
|
||||
font-size: 23px;
|
||||
height: 45px;
|
||||
padding-top: 5px;
|
||||
width: 45px;
|
||||
}
|
||||
|
||||
.system-message {
|
||||
background-color: $color-theme-secondary;
|
||||
border-radius: 50%;
|
||||
color: $color-wild-sand;
|
||||
display: block;
|
||||
font-size: 23px;
|
||||
height: 45px;
|
||||
padding-top: 8px;
|
||||
width: 45px;
|
||||
}
|
||||
|
||||
.notifications-dropdown-header {
|
||||
background-color: $color-theme-primary;
|
||||
color: $color-wild-sand;
|
||||
font-weight: bold;
|
||||
padding: 8px;
|
||||
|
||||
a {
|
||||
color: $color-white;
|
||||
}
|
||||
}
|
||||
|
||||
.notifications-dropdown-footer {
|
||||
background-color: $color-mystic;
|
||||
padding: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.notification {
|
||||
padding-right: 8px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
#search-menu {
|
||||
padding-right: 0;
|
||||
|
||||
.nav {
|
||||
position: relative;
|
||||
z-index: 1000;
|
||||
}
|
||||
}
|
||||
|
||||
#search-content {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
#search-container {
|
||||
padding-left: 45px;
|
||||
}
|
||||
|
||||
#search-bar {
|
||||
border-color: $color-border;
|
||||
.btn-default {
|
||||
background-color: $color-theme-primary;
|
||||
border-color: $color-theme-primary;
|
||||
color: $color-white;
|
||||
}
|
||||
|
||||
input {
|
||||
border-bottom-left-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
/** Search */
|
||||
.nav-search {
|
||||
li.disabled {
|
||||
opacity: .8;
|
||||
|
||||
.badge {
|
||||
background-color: $color-emperor;
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.repositories-team {
|
||||
padding: 10px 15px;
|
||||
|
||||
&.active {
|
||||
color: $color-theme-primary;
|
||||
}
|
||||
}
|
||||
|
||||
.repository-search {
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.notification-settings-container {
|
||||
margin-bottom: 50px;
|
||||
margin-top: 50px;
|
||||
|
||||
h4 {
|
||||
font-weight: 600;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.col-sm-4 {
|
||||
padding-left: 5rem;
|
||||
padding-top: .5rem;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.col-sm-2 {
|
||||
padding-left: 3rem;
|
||||
padding-top: .7rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.col-sm-4 {
|
||||
margin-bottom: 1rem;
|
||||
padding-left: 1.8rem;
|
||||
}
|
||||
|
||||
.col-sm-2 {
|
||||
padding-left: 1.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.assignment {
|
||||
background-color: $color-theme-primary;
|
||||
border-radius: 50%;
|
||||
color: $color-wild-sand;
|
||||
display: block !important;
|
||||
font-size: 15px;
|
||||
height: 30px;
|
||||
margin-right: 15px;
|
||||
padding: 7px;
|
||||
padding-bottom: 5px;
|
||||
padding-top: 5px;
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.system-message {
|
||||
background-color: $color-theme-secondary;
|
||||
border-radius: 50%;
|
||||
color: $color-wild-sand;
|
||||
display: block !important;
|
||||
font-size: 15px;
|
||||
height: 30px;
|
||||
margin-right: 15px;
|
||||
padding: 8px;
|
||||
padding-bottom: 5px;
|
||||
padding-top: 5px;
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.img-circle {
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
// Global team switch
|
||||
#team-switch {
|
||||
word-wrap: break-word;
|
||||
|
||||
.team-name {
|
||||
margin-left: 17px;
|
||||
}
|
||||
|
||||
.glyphicon-ok-sign {
|
||||
color: $color-confirmation-green;
|
||||
margin-left: -10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.team-name-item {
|
||||
border-bottom: 1px solid $color-list-separator;
|
||||
padding-bottom: 8px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
border-bottom-left-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
text-align: right;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
border-color: $color-border;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: $color-theme-primary;
|
||||
border-color: $color-theme-primary;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.caret {
|
||||
color: $color-white;
|
||||
}
|
||||
|
||||
i {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
li {
|
||||
display: block;
|
||||
text-align: left;
|
||||
word-wrap: break-word;
|
||||
|
||||
&:hover {
|
||||
background-color: $color-concrete;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $color-emperor;
|
||||
display: block;
|
||||
line-height: 1.6em;
|
||||
padding: 3px 20px;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#nav-team-switch {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.custom-nav-dropdown {
|
||||
border: 1px solid $color-border;
|
||||
padding: 10px 0 10px 30px;
|
||||
}
|
||||
|
||||
// Alert
|
||||
.alert {
|
||||
border-radius: 0;
|
||||
margin-bottom: 0;
|
||||
opacity: .86;
|
||||
width: 100%;
|
||||
|
||||
&.alert-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a#hide-alert {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
&.alert-floating {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
z-index: 1000;
|
||||
}
|
||||
}
|
||||
|
||||
#content-wrapper {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
|
||||
// reset margins on small screens
|
||||
@media (max-width: 1188px) {
|
||||
|
||||
#nav-team-switch {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
@import 'constants';
|
||||
@import "mixins";
|
||||
@import "main_navigation";
|
||||
@import "buttons";
|
||||
|
||||
/** Layout **/
|
||||
|
||||
|
|
@ -27,10 +29,6 @@ table {
|
|||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#main-nav {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#project-archive-btn {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
|
@ -60,159 +58,16 @@ table {
|
|||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
#content-wrapper {
|
||||
margin-top: 50px;
|
||||
margin-left: 83px;
|
||||
|
||||
&.alert-shown {
|
||||
margin-top: 102px;
|
||||
}
|
||||
}
|
||||
|
||||
.center-block-narrow {
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
#notifications-dropdown {
|
||||
.fa-bell {
|
||||
font-size: 15px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#count-notifications {
|
||||
background-color: $color-theme-primary;
|
||||
border-radius: 5px;
|
||||
color: $color-wild-sand;
|
||||
display: none;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
margin-left: 12px;
|
||||
padding: 1px 6px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-width:450px) {
|
||||
.dropdown-notifications {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-notifications {
|
||||
max-height: 500px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
padding-bottom: 0;
|
||||
padding-top: 0;
|
||||
width: 450px;
|
||||
word-wrap: break-word;
|
||||
|
||||
.notifications-no-recent {
|
||||
padding-bottom: 10px;
|
||||
padding-left: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.notification {
|
||||
border-bottom: 1px solid $color-alto;
|
||||
padding-bottom: 10px;
|
||||
padding-top: 10px;
|
||||
|
||||
&:hover {
|
||||
background-color: $color-concrete;
|
||||
}
|
||||
}
|
||||
|
||||
.unseen {
|
||||
border-left: 4px solid $color-theme-primary;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
top: 0px;
|
||||
margin-top: 5px;
|
||||
height: 45px;
|
||||
width: 45px;
|
||||
}
|
||||
|
||||
.assignment {
|
||||
background-color: $color-theme-primary;
|
||||
border-radius: 50%;
|
||||
color: $color-wild-sand;
|
||||
display: block;
|
||||
font-size: 23px;
|
||||
height: 45px;
|
||||
padding-top: 5px;
|
||||
width: 45px;
|
||||
}
|
||||
|
||||
.deliver {
|
||||
background-color: $color-orange;
|
||||
border-radius: 50%;
|
||||
color: $color-wild-sand;
|
||||
display: block;
|
||||
font-size: 23px;
|
||||
height: 45px;
|
||||
padding-top: 5px;
|
||||
width: 45px;
|
||||
}
|
||||
|
||||
.system-message {
|
||||
background-color: $color-theme-secondary;
|
||||
border-radius: 50%;
|
||||
color: $color-wild-sand;
|
||||
display: block;
|
||||
font-size: 23px;
|
||||
height: 45px;
|
||||
padding-top: 8px;
|
||||
width: 45px;
|
||||
}
|
||||
|
||||
.notifications-dropdown-header {
|
||||
background-color: $color-theme-primary;
|
||||
color: $color-wild-sand;
|
||||
font-weight: bold;
|
||||
padding: 8px;
|
||||
|
||||
a {
|
||||
color: $color-white;
|
||||
}
|
||||
}
|
||||
|
||||
.notifications-dropdown-footer {
|
||||
background-color: $color-mystic;
|
||||
padding: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.notification {
|
||||
padding-right: 8px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
#search-menu {
|
||||
padding-right: 0;
|
||||
|
||||
.nav {
|
||||
position: relative;
|
||||
z-index: 1000;
|
||||
}
|
||||
}
|
||||
|
||||
#search-content {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
#search-container {
|
||||
padding-left: 45px;
|
||||
}
|
||||
|
||||
.well-search-checklist {
|
||||
background-color: $color-concrete !important;
|
||||
margin-bottom: 5px;
|
||||
|
|
@ -253,27 +108,6 @@ a {
|
|||
background-color: inherit;
|
||||
}
|
||||
|
||||
.alert {
|
||||
border-radius: 0;
|
||||
margin-bottom: 0;
|
||||
opacity: 1;
|
||||
width: 100%;
|
||||
|
||||
&.alert-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a#hide-alert {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
&.alert-floating {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
z-index: 1000;
|
||||
}
|
||||
}
|
||||
|
||||
.badge {
|
||||
background-color: $color-theme-primary;
|
||||
font-size: 11px;
|
||||
|
|
@ -302,76 +136,6 @@ a {
|
|||
width: 100% !important;
|
||||
}
|
||||
|
||||
.btn {
|
||||
border-radius: 1.5em;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: $color-theme-secondary;
|
||||
border-color: darken($color-theme-secondary, 5%);
|
||||
|
||||
&.active,
|
||||
&.focus,
|
||||
&.active.focus {
|
||||
background-color: darken($color-theme-secondary, 20%);
|
||||
border-color: darken($color-theme-secondary, 25%);
|
||||
|
||||
&:hover {
|
||||
background-color: darken($color-theme-secondary, 25%);
|
||||
border-color: darken($color-theme-secondary, 30%);
|
||||
}
|
||||
}
|
||||
|
||||
&:active,
|
||||
&:focus,
|
||||
&:active:focus,
|
||||
&:active:hover,
|
||||
&:focus:hover,
|
||||
&:active:focus:hover {
|
||||
background-color: darken($color-theme-secondary, 20%);
|
||||
border-color: darken($color-theme-secondary, 25%);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: darken($color-theme-secondary, 5%);
|
||||
border-color: darken($color-theme-secondary, 10%);
|
||||
}
|
||||
}
|
||||
.btn-link-alt {
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-right: 5px;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.btn-invis-file {
|
||||
display: none;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.btn-open-file {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
& > input[type=file] {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
font-size: 100px;
|
||||
text-align: right;
|
||||
filter: alpha(opacity=0);
|
||||
opacity: 0;
|
||||
outline: none;
|
||||
background: white;
|
||||
cursor: inherit;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
mark,.mark {
|
||||
background-color: $color-candlelight;
|
||||
}
|
||||
|
|
@ -394,43 +158,6 @@ mark,.mark {
|
|||
}
|
||||
}
|
||||
|
||||
.navbar {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.navbar-default {
|
||||
background-color: $color-white;
|
||||
border-color: $color-alto;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-brand {
|
||||
background-color: $color-theme-primary;
|
||||
font-size: 23px;
|
||||
|
||||
& > img {
|
||||
margin-top: -4px;
|
||||
max-width: 132px;
|
||||
max-height: 26px;
|
||||
|
||||
&.with-version {
|
||||
margin-top: -10px;
|
||||
}
|
||||
}
|
||||
|
||||
& > span.version {
|
||||
font-size: 0.6em;
|
||||
color: $color-white;
|
||||
float: right;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:focus:active,
|
||||
&:focus:visited {
|
||||
background-color: $color-theme-primary;
|
||||
}
|
||||
}
|
||||
|
||||
a[data-toggle="tooltip"] {
|
||||
color: inherit;
|
||||
border-bottom: 1px dashed $color-emperor;
|
||||
|
|
@ -587,85 +314,6 @@ a[data-toggle="tooltip"] {
|
|||
padding: 10px;
|
||||
}
|
||||
|
||||
/** Search */
|
||||
.nav-search {
|
||||
li.disabled {
|
||||
opacity: 0.8;
|
||||
|
||||
.badge {
|
||||
background-color: $color-emperor;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.repositories-team {
|
||||
padding: 10px 15px;
|
||||
|
||||
&.active {
|
||||
color: $color-theme-primary;
|
||||
}
|
||||
}
|
||||
|
||||
.repository-search {
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.search-dropdown {
|
||||
padding-right: 25px;
|
||||
width: 250px;
|
||||
|
||||
input {
|
||||
width: 230px;
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-width:1000px) {
|
||||
.search-dropdown {
|
||||
width: 270px;
|
||||
|
||||
.form-group {
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Global team switch
|
||||
#team-switch {
|
||||
border-left: 1px solid $color-alto;
|
||||
border-right: 1px solid $color-alto;
|
||||
word-wrap: break-word;
|
||||
|
||||
.dropdown-menu {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
i {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
li {
|
||||
display: block;
|
||||
text-align: left;
|
||||
word-wrap: break-word;
|
||||
|
||||
&:hover {
|
||||
background-color: $color-concrete;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $color-emperor;
|
||||
display: block;
|
||||
line-height: 1.6em;
|
||||
padding: 3px 20px;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Settings */
|
||||
.nav-settings {
|
||||
margin-top: 15px;
|
||||
|
|
@ -691,78 +339,6 @@ a[data-toggle="tooltip"] {
|
|||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.notification-settings-container {
|
||||
margin-bottom: 50px;
|
||||
margin-top: 50px;
|
||||
|
||||
h4 {
|
||||
font-weight: 600;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.col-sm-4 {
|
||||
padding-left: 5rem;
|
||||
padding-top: .5rem;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.col-sm-2 {
|
||||
padding-left: 3rem;
|
||||
padding-top: .7rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.col-sm-4 {
|
||||
margin-bottom: 1rem;
|
||||
padding-left: 1.8rem;
|
||||
}
|
||||
|
||||
.col-sm-2 {
|
||||
padding-left: 1.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.assignment {
|
||||
background-color: $color-theme-primary;
|
||||
border-radius: 50%;
|
||||
color: $color-wild-sand;
|
||||
display: block !important;
|
||||
font-size: 15px;
|
||||
height: 30px;
|
||||
margin-right: 15px;
|
||||
padding: 7px;
|
||||
padding-bottom: 5px;
|
||||
padding-top: 5px;
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.system-message {
|
||||
background-color: $color-theme-secondary;
|
||||
border-radius: 50%;
|
||||
color: $color-wild-sand;
|
||||
display: block !important;
|
||||
font-size: 15px;
|
||||
height: 30px;
|
||||
margin-right: 15px;
|
||||
padding: 8px;
|
||||
padding-bottom: 5px;
|
||||
padding-top: 5px;
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.img-circle {
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
#reset-tutorial-btn {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
// Help link
|
||||
#help-link {
|
||||
padding: 13px;
|
||||
|
|
@ -780,26 +356,6 @@ a[data-toggle="tooltip"] {
|
|||
padding-left: 15px;
|
||||
}
|
||||
|
||||
/** Add users modal */
|
||||
.btn-group-existing-users {
|
||||
width: 100%;
|
||||
|
||||
label.btn {
|
||||
text-align: center;
|
||||
|
||||
&.btn-title {
|
||||
color: $color-white;
|
||||
cursor: inherit;
|
||||
background-color: $color-theme-primary;
|
||||
|
||||
&:focus, &:active, &:hover {
|
||||
box-shadow: none;
|
||||
background-color: $color-theme-primary;
|
||||
border-color: $color-dark-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.existing-users-smalltext {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
|
|
@ -1429,18 +985,6 @@ ul.content-module-activities {
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
.btn-greyed {
|
||||
background-color: $color-silver-chalice;
|
||||
border-color: $color-silver-chalice;
|
||||
color: $color-white;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: darken($color-silver-chalice, 15%);
|
||||
border-color: darken($color-silver-chalice, 15%);
|
||||
color: $color-white;
|
||||
}
|
||||
}
|
||||
/* Data table */
|
||||
|
||||
table.dataTable {
|
||||
|
|
@ -1500,13 +1044,6 @@ table.dataTable {
|
|||
}
|
||||
}
|
||||
|
||||
/* Sample group color picker */
|
||||
.btn-group-sample-group-color {
|
||||
.btn-group > .btn {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
#samples_length {
|
||||
display: inline-block;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ class MyModuleRepositoryRow < ApplicationRecord
|
|||
foreign_key: 'assigned_by_id',
|
||||
class_name: 'User',
|
||||
optional: true
|
||||
belongs_to :repository_row, optional: true
|
||||
belongs_to :my_module, optional: true
|
||||
belongs_to :repository_row,
|
||||
optional: true,
|
||||
inverse_of: :my_module_repository_rows
|
||||
belongs_to :my_module, optional: true, inverse_of: :my_module_repository_rows
|
||||
|
||||
validates :repository_row, :my_module, presence: true
|
||||
validates :repository_row, uniqueness: { scope: :my_module }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
class Repository < ApplicationRecord
|
||||
include SearchableModel
|
||||
include RepositoryImportParser
|
||||
|
||||
belongs_to :team, optional: true
|
||||
belongs_to :created_by,
|
||||
|
|
@ -95,87 +96,8 @@ class Repository < ApplicationRecord
|
|||
new_repo
|
||||
end
|
||||
|
||||
# Imports records
|
||||
def import_records(sheet, mappings, user)
|
||||
errors = false
|
||||
columns = []
|
||||
name_index = -1
|
||||
total_nr = 0
|
||||
nr_of_added = 0
|
||||
header_skipped = false
|
||||
|
||||
mappings.each.with_index do |(_k, value), index|
|
||||
if value == '-1'
|
||||
# Fill blank space, so our indices stay the same
|
||||
columns << nil
|
||||
name_index = index
|
||||
else
|
||||
columns << repository_columns.find_by_id(value)
|
||||
end
|
||||
end
|
||||
|
||||
# Check for duplicate columns
|
||||
col_compact = columns.compact
|
||||
unless col_compact.map(&:id).uniq.length == col_compact.length
|
||||
return { status: :error, nr_of_added: nr_of_added, total_nr: total_nr }
|
||||
end
|
||||
rows = SpreadsheetParser.spreadsheet_enumerator(sheet)
|
||||
|
||||
# Now we can iterate through record data and save stuff into db
|
||||
rows.each do |row|
|
||||
# Skip empty rows
|
||||
next if row.empty?
|
||||
unless header_skipped
|
||||
header_skipped = true
|
||||
next
|
||||
end
|
||||
total_nr += 1
|
||||
|
||||
row = SpreadsheetParser.parse_row(row, sheet)
|
||||
|
||||
record_row = RepositoryRow.new(name: row[name_index],
|
||||
repository: self,
|
||||
created_by: user,
|
||||
last_modified_by: user)
|
||||
record_row.transaction do
|
||||
unless record_row.save
|
||||
errors = true
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
|
||||
row_cell_values = []
|
||||
|
||||
row.each.with_index do |value, index|
|
||||
if columns[index] && value
|
||||
cell_value = RepositoryTextValue.new(
|
||||
data: value,
|
||||
created_by: user,
|
||||
last_modified_by: user,
|
||||
repository_cell_attributes: {
|
||||
repository_row: record_row,
|
||||
repository_column: columns[index]
|
||||
}
|
||||
)
|
||||
unless cell_value.valid?
|
||||
errors = true
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
row_cell_values << cell_value
|
||||
end
|
||||
end
|
||||
if RepositoryTextValue.import(row_cell_values,
|
||||
recursive: true,
|
||||
validate: false).failed_instances.any?
|
||||
errors = true
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
nr_of_added += 1
|
||||
end
|
||||
end
|
||||
|
||||
if errors
|
||||
return { status: :error, nr_of_added: nr_of_added, total_nr: total_nr }
|
||||
end
|
||||
{ status: :ok, nr_of_added: nr_of_added, total_nr: total_nr }
|
||||
importer = RepositoryImportParser::Importer.new(sheet, mappings, user, self)
|
||||
importer.run
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
class RepositoryCell < ActiveRecord::Base
|
||||
belongs_to :repository_row
|
||||
belongs_to :repository_column
|
||||
belongs_to :value, polymorphic: true, dependent: :destroy
|
||||
belongs_to :value, polymorphic: true,
|
||||
inverse_of: :repository_cell,
|
||||
dependent: :destroy
|
||||
belongs_to :repository_text_value,
|
||||
(lambda do
|
||||
where(repository_cells: { value_type: 'RepositoryTextValue' })
|
||||
|
|
|
|||
129
app/utilities/repository_import_parser/importer.rb
Normal file
129
app/utilities/repository_import_parser/importer.rb
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# handles the import of repository records
|
||||
# requires 4 parameters:
|
||||
# @sheet: the csv file with imported rows
|
||||
# @mappings: mappings for columns
|
||||
# @user: current_user
|
||||
# @repository: the repository in which we import the items
|
||||
module RepositoryImportParser
|
||||
class Importer
|
||||
def initialize(sheet, mappings, user, repository)
|
||||
@columns = []
|
||||
@name_index = -1
|
||||
@total_new_rows = 0
|
||||
@new_rows_added = 0
|
||||
@header_skipped = false
|
||||
@repository = repository
|
||||
@sheet = sheet
|
||||
@rows = SpreadsheetParser.spreadsheet_enumerator(@sheet)
|
||||
@mappings = mappings
|
||||
@user = user
|
||||
@repository_columns = @repository.repository_columns
|
||||
end
|
||||
|
||||
def run
|
||||
fetch_columns
|
||||
return check_for_duplicate_columns if check_for_duplicate_columns
|
||||
import_rows!
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_columns
|
||||
@mappings.each.with_index do |(_, value), index|
|
||||
if value == '-1'
|
||||
# Fill blank space, so our indices stay the same
|
||||
@columns << nil
|
||||
@name_index = index
|
||||
else
|
||||
@columns << @repository_columns.find_by_id(value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def check_for_duplicate_columns
|
||||
col_compact = @columns.compact
|
||||
if col_compact.map(&:id).uniq.length != col_compact.length
|
||||
return { status: :error,
|
||||
nr_of_added: @new_rows_added,
|
||||
total_nr: @total_new_rows }
|
||||
end
|
||||
end
|
||||
|
||||
def import_rows!
|
||||
errors = false
|
||||
@rows.each do |row|
|
||||
# Skip empty rows
|
||||
next if row.empty?
|
||||
unless @header_skipped
|
||||
@header_skipped = true
|
||||
next
|
||||
end
|
||||
@total_new_rows += 1
|
||||
|
||||
row = SpreadsheetParser.parse_row(row, @sheet)
|
||||
record_row = new_repository_row(row)
|
||||
record_row.transaction do
|
||||
unless record_row.save
|
||||
errors = true
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
|
||||
row_cell_values = []
|
||||
|
||||
row.each.with_index do |value, index|
|
||||
column = @columns[index]
|
||||
if column && value.present?
|
||||
# uses RepositoryCellValueResolver to retrieve the correct value
|
||||
cell_value_resolver =
|
||||
RepositoryImportParser::RepositoryCellValueResolver.new(
|
||||
column, @user, @repository
|
||||
)
|
||||
cell_value = cell_value_resolver.get_value(value, record_row)
|
||||
unless cell_value.valid?
|
||||
errors = true
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
row_cell_values << cell_value
|
||||
end
|
||||
end
|
||||
|
||||
unless import_to_database(row_cell_values)
|
||||
errors = true
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
@new_rows_added += 1
|
||||
end
|
||||
end
|
||||
|
||||
if errors
|
||||
return { status: :error,
|
||||
nr_of_added: @new_rows_added,
|
||||
total_nr: @total_new_rows }
|
||||
end
|
||||
{ status: :ok, nr_of_added: @new_rows_added, total_nr: @total_new_rows }
|
||||
end
|
||||
|
||||
def new_repository_row(row)
|
||||
RepositoryRow.new(name: row[@name_index],
|
||||
repository: @repository,
|
||||
created_by: @user,
|
||||
last_modified_by: @user)
|
||||
end
|
||||
|
||||
def import_to_database(row_cell_values)
|
||||
return false if RepositoryTextValue.import(
|
||||
row_cell_values.select { |element| element.is_a? RepositoryTextValue },
|
||||
recursive: true,
|
||||
validate: false
|
||||
).failed_instances.any?
|
||||
return false if RepositoryListValue.import(
|
||||
row_cell_values.select { |element| element.is_a? RepositoryListValue },
|
||||
recursive: true,
|
||||
validate: false
|
||||
).failed_instances.any?
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# this class is used to resolve the column data_type and assign
|
||||
# it to the repository_row
|
||||
module RepositoryImportParser
|
||||
class RepositoryCellValueResolver
|
||||
def initialize(column, user, repository)
|
||||
@column = column
|
||||
@user = user
|
||||
@repository = repository
|
||||
end
|
||||
|
||||
def get_value(value, record_row)
|
||||
return unless @column
|
||||
send("new_#{@column.data_type.underscore}", value, record_row)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def new_repository_text_value(value, record_row)
|
||||
RepositoryTextValue.new(data: value,
|
||||
created_by: @user,
|
||||
last_modified_by: @user,
|
||||
repository_cell_attributes: {
|
||||
repository_row: record_row,
|
||||
repository_column: @column
|
||||
})
|
||||
end
|
||||
|
||||
def new_repository_list_value(value, record_row)
|
||||
list_item = @column.repository_list_items.find_by_data(value)
|
||||
list_item ||= create_repository_list_item(value)
|
||||
RepositoryListValue.new(
|
||||
created_by: @user,
|
||||
last_modified_by: @user,
|
||||
repository_list_item: list_item,
|
||||
repository_cell_attributes: {
|
||||
repository_row: record_row,
|
||||
repository_column: @column
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
def create_repository_list_item(value)
|
||||
RepositoryListItem.create(
|
||||
data: value,
|
||||
created_by: @user,
|
||||
last_modified_by: @user,
|
||||
repository_column: @column,
|
||||
repository: @repository
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -65,7 +65,7 @@
|
|||
</div>
|
||||
|
||||
<%= render "shared/left_menu_bar" if user_signed_in? %>
|
||||
<div id="content-wrapper" class="<%= "alert-shown" if flash[:success] || flash[:error] || notice || alert %>">
|
||||
<div id="content-wrapper">
|
||||
<%= yield :content %>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<nav class="navbar navbar-default navbar-fixed-top" id="main-nav">
|
||||
<div class="container">
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- header -->
|
||||
<div class="navbar-header">
|
||||
|
|
@ -10,166 +10,105 @@
|
|||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<%= link_to(root_path, class: 'navbar-brand', title: t('nav.label.scinote')) do %>
|
||||
<%
|
||||
show_version = !Rails.env.production?
|
||||
if ENV['NAVBAR_SHOW_VERSION'].present?
|
||||
show_version = YAML.load(ENV['NAVBAR_SHOW_VERSION'])
|
||||
end
|
||||
%>
|
||||
<% if show_version %>
|
||||
<%= image_tag('/images/logo.png', class: 'with-version', id: 'logo') %>
|
||||
<span class="version">
|
||||
<%= Scinote::Application::VERSION %>
|
||||
</span>
|
||||
<% else %>
|
||||
<%= image_tag('/images/logo.png', id: 'logo') %>
|
||||
<% end %>
|
||||
<%= image_tag('/images/scinote_icon.jpg', id: 'logo') %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if user_signed_in? %>
|
||||
<div class="collapse navbar-collapse" id="main-menu">
|
||||
<!-- links -->
|
||||
<ul class="nav navbar-nav">
|
||||
<li>
|
||||
<a title="<%= t('nav.label.projects') %>" href="<%= projects_path %>">
|
||||
<span class="glyphicon glyphicon-home"></span>
|
||||
<span class="visible-xs-inline visible-sm-inline"><%= t('nav.label.projects') %></span>
|
||||
</a>
|
||||
</li>
|
||||
<% if current_team %>
|
||||
<li>
|
||||
<a id="protocol-link" title="<%= t('nav.label.protocols') %>" href="<%= protocols_path %>">
|
||||
<span class="glyphicon glyphicon-list-alt"></span>
|
||||
<span class="visible-xs-inline visible-sm-inline"><%= t('nav.label.protocols') %></span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a id="repositories-link" title="<%= t('nav.label.repositories') %>" href="<%= team_repositories_path(current_team) %>">
|
||||
<i class="fa fa-cubes" aria-hidden="true"></i>
|
||||
<span class="visible-xs-inline visible-sm-inline"><%= t('nav.label.repositories') %></span>
|
||||
</a>
|
||||
</li>
|
||||
<% else %>
|
||||
<li class="disabled">
|
||||
<a id="protocol-link" title="<%= t('nav.label.protocols') %>" href="#">
|
||||
<span class="glyphicon glyphicon-list-alt"></span>
|
||||
<span class="visible-xs-inline visible-sm-inline"><%= t('nav.label.protocols') %></span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="disabled">
|
||||
<a id="repositories-link" title="<%= t('nav.label.repositories') %>" href="#">
|
||||
<span class="fa fa-cubes"></span>
|
||||
<span class="visible-xs-inline visible-sm-inline"><%= t('nav.label.repositories') %></span>
|
||||
</a>
|
||||
</li>
|
||||
<ul class="nav navbar-nav navbar-left" id="nav-team-switch">
|
||||
<!-- Global team switch -->
|
||||
<% if current_user.teams.length > 0 %>
|
||||
<li id="team-switch">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default"><%= truncate_team_name(current_team.name) %></button>
|
||||
<button type="button"
|
||||
class="btn btn-primary dropdown-toggle"
|
||||
title="<%= t('nav.label.teams') %>"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
<span class="caret"></span>
|
||||
<span class="sr-only">Toggle Dropdown</span>
|
||||
</button>
|
||||
<% if current_user.teams.length > 1 || can_create_teams? %>
|
||||
<ul class="dropdown-menu">
|
||||
<%= form_for(current_user,
|
||||
url: user_current_team_path,
|
||||
method: :post) do |f| %>
|
||||
<%= hidden_field(:user, :current_team_id) %>
|
||||
<% current_user.teams.each do |team| %>
|
||||
<li class="team-name-item">
|
||||
<a href="#"
|
||||
data-id="<%= team.id %>"
|
||||
class="text-center change-team">
|
||||
<% if current_team == team %>
|
||||
<span class="glyphicon glyphicon-ok-sign"></span> <strong><%= team.name %></strong>
|
||||
<% else %>
|
||||
<span class="team-name"><%= team.name %></span>
|
||||
<% end %>
|
||||
</a>
|
||||
</li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% if current_user.teams.length > 1 && can_create_teams? %>
|
||||
<li>
|
||||
<%= link_to new_team_path do %>
|
||||
<span class="glyphicon glyphicon-plus"></span>
|
||||
<%= t('users.settings.teams.index.new_team') %>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
</div>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if false %>
|
||||
<li>
|
||||
<a href="#">
|
||||
<span class="glyphicon glyphicon-calendar"></span>
|
||||
<span class="visible-xs-inline visible-sm-inline"><%= t('nav.label.calendar') %></span>
|
||||
</a>
|
||||
</li>
|
||||
<% end %>
|
||||
<li>
|
||||
<a class="btn-activity" title="<%= t('nav.label.activities') %>" href="<%= activities_path %>" role="button">
|
||||
<span class="glyphicon glyphicon-equalizer"></span>
|
||||
<span class="visible-xs-inline visible-sm-inline"><%= t('nav.label.activities') %></span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- profile info -->
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
|
||||
<!-- Global team switch -->
|
||||
<% if current_user.teams.length > 0 %>
|
||||
<li class="dropdown" id="team-switch">
|
||||
<a href="#"
|
||||
class="dropdown-toggle"
|
||||
title="<%= t('nav.label.teams') %>"
|
||||
data-toggle="dropdown"
|
||||
role="button"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
<%= fa_icon 'users' %>
|
||||
<span>
|
||||
<%= truncate_team_name(current_team.name) %>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<% if current_user.teams.length > 1 || can_create_teams? %>
|
||||
<ul class="dropdown-menu">
|
||||
<%= form_for(current_user,
|
||||
url: user_current_team_path,
|
||||
method: :post) do |f| %>
|
||||
<%= hidden_field(:user, :current_team_id) %>
|
||||
<% current_user.teams.each do |team| %>
|
||||
<% next unless team != current_team %>
|
||||
<li>
|
||||
<a href="#"
|
||||
data-id="<%= team.id %>"
|
||||
class="text-center change-team">
|
||||
<%= team.name %>
|
||||
</a>
|
||||
</li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% if current_user.teams.length > 1 && can_create_teams? %>
|
||||
<li role="separator"
|
||||
class="divider"></li>
|
||||
<li>
|
||||
<%= link_to new_team_path do %>
|
||||
<span class="glyphicon glyphicon-plus"></span>
|
||||
<%= t('users.settings.teams.index.new_team') %>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<!-- search form -->
|
||||
<li>
|
||||
<%= form_tag search_path,
|
||||
method: :get,
|
||||
id: 'search-bar',
|
||||
class: 'navbar-form',
|
||||
role: 'search' do %>
|
||||
<div class="input-group">
|
||||
<input class="form-control"
|
||||
type="text"
|
||||
name="q"
|
||||
placeholder="<%= t('nav.search') %>" />
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default" type="submit"><%=t 'nav.search_button' %></button>
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<!-- search -->
|
||||
<li class="dropdown"
|
||||
id="search-ico">
|
||||
<!-- greetings -->
|
||||
<li id="user-account-dropdown" class="dropdown">
|
||||
<a href="#"
|
||||
class="dropdown-toggle"
|
||||
title="<%= t('nav.label.search') %>"
|
||||
title="<%= t('nav.label.account') %>"
|
||||
data-toggle="dropdown"
|
||||
role="button"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
<span class="glyphicon glyphicon-search"></span>
|
||||
<span class="visible-xs-inline visible-sm-inline"><%= t('nav.label.search') %></span>
|
||||
<span>
|
||||
<%= t('nav.user_greeting', full_name: current_user.full_name) %>
|
||||
</span>
|
||||
<%= image_tag avatar_path(current_user, :icon_small),
|
||||
class: "avatar" %>
|
||||
</a>
|
||||
<ul class="dropdown-menu search-dropdown">
|
||||
<li>
|
||||
<!-- search form -->
|
||||
<%= form_tag search_path,
|
||||
method: :get,
|
||||
id: 'search-bar',
|
||||
class: 'navbar-form navbar-right',
|
||||
role: 'search' do %>
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<input class="form-control"
|
||||
type="text"
|
||||
name="q"
|
||||
placeholder="<%= t('nav.search') %>">
|
||||
<span class="input-group-btn visible-xs visible-sm">
|
||||
<button id="search-button"
|
||||
class="btn btn-default"
|
||||
type="submit">
|
||||
<span class="glyphicon glyphicon-menu-right"></span>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="dropdown-menu" data-hook="navigation-user-menu">
|
||||
<li>
|
||||
<%= link_to t('nav.user.logout'),
|
||||
destroy_user_session_path,
|
||||
method: :delete %>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<!-- notifications -->
|
||||
|
|
@ -205,71 +144,6 @@
|
|||
</ul>
|
||||
</li>
|
||||
|
||||
<!-- help -->
|
||||
<li class="dropdown">
|
||||
<a href="#"
|
||||
id="help-link"
|
||||
class="dropdown-toggle"
|
||||
title="<%= t('nav.label.info') %>"
|
||||
data-toggle="dropdown"
|
||||
role="button"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
<span class="glyphicon glyphicon-info-sign"></span>
|
||||
<span class="visible-xs-inline visible-sm-inline"><%= t('nav.label.info') %></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu" data-hook="navigation-help-menu">
|
||||
<li><%= link_to t('nav.help.support'),
|
||||
Constants::SUPPORT_URL,
|
||||
target: "_blank" %></li>
|
||||
<li><%= link_to t('nav.help.tutorials'),
|
||||
Constants::TUTORIALS_URL,
|
||||
target: "_blank" %></li>
|
||||
<li><%= link_to t('nav.help.release_notes'),
|
||||
Constants::RELEASE_NOTES_URL,
|
||||
target: "_blank" %></li>
|
||||
<li><%= link_to t('nav.help.premium'),
|
||||
Constants::PREMIUM_URL,
|
||||
target: "_blank" %></li>
|
||||
<li><%= link_to t('nav.help.contact'),
|
||||
Constants::CONTACT_URL,
|
||||
target: "_blank" %></li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<li>
|
||||
<%= link_to '#', data: { trigger: 'about-modal' } do %>
|
||||
<%= t('nav.help.about') %>
|
||||
<% end %>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<!-- greetings -->
|
||||
<li id="user-account-dropdown" class="dropdown">
|
||||
<a href="#"
|
||||
class="dropdown-toggle"
|
||||
title="<%= t('nav.label.account') %>"
|
||||
data-toggle="dropdown"
|
||||
role="button"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
<span>
|
||||
<%= t('nav.user_greeting', full_name: current_user.full_name) %>
|
||||
</span>
|
||||
<%= image_tag avatar_path(current_user, :icon_small),
|
||||
class: "avatar" %>
|
||||
</a>
|
||||
<ul class="dropdown-menu" data-hook="navigation-user-menu">
|
||||
<li>
|
||||
<%= link_to t('nav.user.settings'), edit_user_registration_path, data: { turbolinks: false } %>
|
||||
</li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<li>
|
||||
<%= link_to t('nav.user.logout'),
|
||||
destroy_user_session_path,
|
||||
method: :delete %>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
|||
|
|
@ -67,7 +67,8 @@ en:
|
|||
body:
|
||||
notice: "You need to enable JavaScript to run this app."
|
||||
nav:
|
||||
search: "Search"
|
||||
search: "Search for something..."
|
||||
search_button: 'Go!'
|
||||
user_greeting: "Hi, %{full_name}"
|
||||
advanced_search: "Advanced search"
|
||||
title: "sciNote"
|
||||
|
|
@ -986,12 +987,12 @@ en:
|
|||
|
||||
repository_row:
|
||||
modal_info:
|
||||
head_title: "Information for record '%{repository_row}'"
|
||||
head_title: "Information for item '%{repository_row}'"
|
||||
added_on: "Added on"
|
||||
added_by: "Added by"
|
||||
custom_field: "%{cf}: "
|
||||
title: "This record is assigned to %{nr} tasks."
|
||||
no_tasks: "This record in not assigned to any task."
|
||||
title: "This item is assigned to %{nr} tasks."
|
||||
no_tasks: "This item in not assigned to any task."
|
||||
samples:
|
||||
columns: "Columns"
|
||||
columns_visibility: "Toggle visibility"
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ Scenario: Unsuccessful Log in
|
|||
And I click "Log in" button
|
||||
Then I should see "Invalid Email or password." flash message
|
||||
|
||||
@javascript
|
||||
@javascript @wip
|
||||
Scenario: Successful Log out
|
||||
Given "night.slarker@gmail.com" is signed in with "mypassword1234"
|
||||
And I'm on the home page of "BioSistemika Process" team
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ Background:
|
|||
And "nonadmin@myorg.com" is in "BioSistemika Process" team as a "normal_user"
|
||||
And "nonadmin@myorg.com" is signed in with "mypassword1234"
|
||||
|
||||
@javascript
|
||||
@javascript @wip
|
||||
Scenario: Successful navigate to profile page
|
||||
Given I'm on the home page of "BioSistemika Process" team
|
||||
And I click on Avatar
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ require 'capybara/email'
|
|||
Capybara.register_driver :poltergeist do |app|
|
||||
options = {
|
||||
# inspector: true,
|
||||
screen_size: [1200, 900],
|
||||
screen_size: [2560, 900],
|
||||
js_errors: false,
|
||||
timeout: 30,
|
||||
phantomjs: Phantomjs.path,
|
||||
|
|
|
|||
BIN
public/images/scinote_icon.jpg
Normal file
BIN
public/images/scinote_icon.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6 KiB |
6
spec/fixtures/files/export.csv
vendored
Normal file
6
spec/fixtures/files/export.csv
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
Name,Added on,Added by,Sample group,Sample type,Custom items
|
||||
Sample 5,02.03.2018 09:53,Admin,group 3,,test 3
|
||||
Sample 4,02.03.2018 09:53,Admin,group 2,type 1,test 2
|
||||
Sample 3,02.03.2018 09:53,Admin,,type 1,
|
||||
Sample 2,02.03.2018 09:52,Admin,group 2,type 2,
|
||||
Sample 1,02.03.2018 09:52,Admin,group 1,type 2,test test
|
||||
|
91
spec/utilities/repository_import_parser/importer_spec.rb
Normal file
91
spec/utilities/repository_import_parser/importer_spec.rb
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe RepositoryImportParser::Importer do
|
||||
let(:user) { create :user }
|
||||
let(:team) { create :team, created_by: user }
|
||||
let(:user_team) { create :user_team, user: user, team: team }
|
||||
let(:repository) { create :repository, team: team, created_by: user }
|
||||
let!(:sample_group_column) do
|
||||
create :repository_column, repository: repository,
|
||||
created_by: user,
|
||||
name: 'Sample group',
|
||||
data_type: 'RepositoryListValue'
|
||||
end
|
||||
let!(:sample_type_column) do
|
||||
create :repository_column, repository: repository,
|
||||
created_by: user,
|
||||
name: 'Sample type',
|
||||
data_type: 'RepositoryListValue'
|
||||
end
|
||||
let!(:custom_column) do
|
||||
create :repository_column, repository: repository,
|
||||
created_by: user,
|
||||
name: 'Custom items',
|
||||
data_type: 'RepositoryTextValue'
|
||||
end
|
||||
|
||||
let(:sheet) do
|
||||
SpreadsheetParser.open_spreadsheet(fixture_file_upload('files/export.csv'))
|
||||
end
|
||||
let(:mappings) do
|
||||
{ '0' => '-1',
|
||||
'1' => '',
|
||||
'2' => '',
|
||||
'3' => sample_group_column.id.to_s,
|
||||
'4' => sample_type_column.id.to_s,
|
||||
'5' => custom_column.id.to_s }
|
||||
end
|
||||
|
||||
describe '#run/0' do
|
||||
let(:subject) do
|
||||
RepositoryImportParser::Importer.new(sheet, mappings, user, repository)
|
||||
end
|
||||
|
||||
it 'return a message of imported records' do
|
||||
expect(subject.run).to eq({ status: :ok, nr_of_added: 5, total_nr: 5 })
|
||||
end
|
||||
|
||||
it 'generate 5 new repository rows' do
|
||||
subject.run
|
||||
expect(repository.repository_rows.count).to eq 5
|
||||
end
|
||||
|
||||
it 'generate 3 new repository list items on Sample group column' do
|
||||
subject.run
|
||||
column = repository.repository_columns.find_by_name('Sample group')
|
||||
expect(column.repository_list_items.count).to eq 3
|
||||
column.repository_list_items.each do |repository_item|
|
||||
expect(['group 1', 'group 2', 'group 3']).to include(repository_item.data)
|
||||
end
|
||||
end
|
||||
|
||||
it 'generate 2 new repository list items on Sample type column' do
|
||||
subject.run
|
||||
column = repository.repository_columns.find_by_name('Sample type')
|
||||
expect(column.repository_list_items.count).to eq 2
|
||||
column.repository_list_items.each do |repository_item|
|
||||
expect(['type 1', 'type 2']).to include(repository_item.data)
|
||||
end
|
||||
end
|
||||
|
||||
it 'assign custom columns to imported repository row' do
|
||||
subject.run
|
||||
row = repository.repository_rows.find_by_name('Sample 1')
|
||||
sample_group_cell = row.repository_cells
|
||||
.find_by_repository_column_id(
|
||||
sample_group_column.id
|
||||
)
|
||||
sample_type_cell = row.repository_cells
|
||||
.find_by_repository_column_id(
|
||||
sample_type_column.id
|
||||
)
|
||||
custom_column_cell = row.repository_cells
|
||||
.find_by_repository_column_id(
|
||||
custom_column.id
|
||||
)
|
||||
expect(sample_group_cell.value.formatted).to eq 'group 1'
|
||||
expect(sample_type_cell.value.formatted).to eq 'type 2'
|
||||
expect(custom_column_cell.value.formatted).to eq 'test test'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe RepositoryImportParser::RepositoryCellValueResolver do
|
||||
let(:user) { create :user }
|
||||
let(:team) { create :team, created_by: user }
|
||||
let(:user_team) { create :user_team, user: user, team: team }
|
||||
let(:repository) { create :repository, team: team, created_by: user }
|
||||
let!(:sample_group_column) do
|
||||
create :repository_column, repository: repository,
|
||||
created_by: user,
|
||||
name: 'Sample group',
|
||||
data_type: 'RepositoryListValue'
|
||||
end
|
||||
let!(:custom_column) do
|
||||
create :repository_column, repository: repository,
|
||||
created_by: user,
|
||||
name: 'Custom items',
|
||||
data_type: 'RepositoryTextValue'
|
||||
end
|
||||
|
||||
let!(:repository_row) do
|
||||
create :repository_row, repository: repository,
|
||||
created_by: user,
|
||||
name: 'Sample'
|
||||
end
|
||||
|
||||
describe '#ruget_valuen/2' do
|
||||
context 'RepositoryListValue' do
|
||||
let(:subject) do
|
||||
RepositoryImportParser::RepositoryCellValueResolver.new(
|
||||
sample_group_column, user, repository
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns a valid RepositoryListValue object' do
|
||||
value = subject.get_value('leaf', repository_row)
|
||||
expect(value).to be_valid
|
||||
expect(value).to be_a RepositoryListValue
|
||||
expect(value.formatted).to eq 'leaf'
|
||||
end
|
||||
|
||||
it 'creates a new RepositoryListItem' do
|
||||
value = subject.get_value('leaf', repository_row)
|
||||
item = sample_group_column.repository_list_items.find_by_data('leaf')
|
||||
expect(sample_group_column.repository_list_items.count).to eq 1
|
||||
expect(item).to be_present
|
||||
expect(item.data).to eq 'leaf'
|
||||
end
|
||||
end
|
||||
|
||||
context 'RepositoryTextValue' do
|
||||
let(:subject) do
|
||||
RepositoryImportParser::RepositoryCellValueResolver.new(
|
||||
custom_column, user, repository
|
||||
)
|
||||
|
||||
it 'returns a valid RepositoryTextValue object' do
|
||||
value = subject.get_value('blood', repository_row)
|
||||
expect(value).to be_valid
|
||||
expect(value).to be_a RepositoryTextValue
|
||||
expect(value.formatted).to eq 'blood'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue